ruby-openid-2.7.0debian.orig/0000755000175000017500000000000012512544714015314 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/LICENSE0000644000175000017500000002675212512544714016335 0ustar sbadiasbadiaThe code in lib/hmac/ is Copyright 2001 by Daiki Ueno, and distributed under the terms of the Ruby license. See http://www.ruby-lang.org/en/LICENSE.txt lib/openid/yadis/htmltokenizer.rb is Copyright 2004 by Ben Giddings and distributed under the terms of the Ruby license. The remainder of this package is Copyright 2006-2008 by JanRain, Inc. and distributed under the terms of license below: Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ruby-openid-2.7.0debian.orig/UPGRADE.md0000644000175000017500000001063712512544714016734 0ustar sbadiasbadia# Upgrading from the OpenID 1.x series library ## Consumer Upgrade The flow is largely the same, however there are a number of significant changes. The consumer example is helpful to look at: `examples/rails_openid/app/controllers/consumer_controller.rb` ### Stores You will need to require the file for the store that you are using. For the filesystem store, this is 'openid/stores/filesystem' They are also now in modules. The filesystem store is `OpenID::Store::Filesystem` The format has changed, and you should remove your old store directory. The ActiveRecord store (`examples/active_record_openid_store`) still needs to be put in a plugin directory for your rails app. There's a migration that needs to be run; examine the `README` in that directory. Also, note that the stores now can be garbage collected with the method `store.cleanup` ### Starting the OpenID transaction The OpenIDRequest object no longer has status codes. Instead, consumer.begin raises an OpenID::OpenIDError if there is a problem initiating the transaction, so you'll want something along the lines of: begin openid_request = consumer.begin(params[:openid_identifier]) rescue OpenID::OpenIDError => e # display error e return end #success case Data regarding the OpenID server once lived in `openid_request.service` The corresponding object in the 2.0 lib can be retrieved with `openid_request.endpoint` Getting the unverified identifier: Where you once had `openid_request.identity_url` you will now want `openid_request.endpoint.claimed_id` which might be different from what you get at the end of the transaction, since it is now possible for users to enter their server's url directly. Arguments on the return_to URL are now verified, so if you want to add additional arguments to the return_to url, use `openid_request.return_to_args['param'] = value` Generating the redirect is the same as before, but add any extensions first. If you need to set up an SSL certificate authority list for the fetcher, use the 'ca_file' attr_accessor on the `OpenID::StandardFetcher`. This has changed from 'ca_path' in the 1.x.x series library. That is, set `OpenID.fetcher.ca_file = '/path/to/ca.list'` before calling consumer.begin. ### Requesting Simple Registration Data You'll need to require the code for the extension require 'openid/extensions/sreg' The new code for adding an SReg request now looks like: sreg_request = OpenID::SReg::Request.new sreg_request.request_fields(['email', 'dob'], true) # required sreg_request.request_fields(['nickname', 'fullname'], false) # optional sreg_request.policy_url = policy_url openid_request.add_extension(sreg_request) The code for adding other extensions is similar. Code for the Attribute Exchange (AX) and Provider Authentication Policy Extension (PAPE) are included with the library, and additional extensions can be implemented subclassing `OpenID::Extension`. ### Completing the transaction The return_to and its arguments are verified, so you need to pass in the base URL and the arguments. With Rails, the params method mashes together parameters from GET, POST, and the path, so you'll need to pull off the path "parameters" with something like return_to = url_for(:only_path => false, :controller => 'openid', :action => 'complete') parameters = params.reject{|k,v| request.path_parameters[k] } openid_response = consumer.complete(parameters, return_to) The response still uses the status codes, but they are now namespaced slightly differently, for example `OpenID::Consumer::SUCCESS` In the case of failure, the error message is now found in `openid_response.message` The identifier to display to the user can be found in `openid_response.endpoint.display_identifier` The Simple Registration response can be read from the OpenID response with sreg_response = OpenID::SReg::Response.from_success_response(openid_response) nickname = sreg_response['nickname'] # etc. ## Server Upgrade The server code is mostly the same as before, with the exception of extensions. Also, you must pass in the endpoint URL to the server constructor: @server = OpenID::Server.new(store, server_url) I recommend looking at `examples/rails_openid/app/controllers/server_controller.rb` for an example of the new way of doing extensions. -- Dag Arneson, JanRain Inc. Please direct questions to openid@janrain.com ruby-openid-2.7.0debian.orig/test/0000755000175000017500000000000012512544714016273 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/test/test_filters.rb0000644000175000017500000002013512512544714021330 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "rexml/document" require "openid/yadis/xrds" require "openid/yadis/filters" module OpenID class BasicServiceEndpointTest < Minitest::Test def test_match_types # Make sure the match_types operation returns the expected # results with various inputs. types = ["urn:bogus", "urn:testing"] yadis_url = "http://yadis/" no_types_endpoint = Yadis::BasicServiceEndpoint.new(yadis_url, [], nil, nil) some_types_endpoint = Yadis::BasicServiceEndpoint.new(yadis_url, types, nil, nil) assert(no_types_endpoint.match_types([]) == []) assert(no_types_endpoint.match_types(["urn:absent"]) == []) assert(some_types_endpoint.match_types([]) == []) assert(some_types_endpoint.match_types(["urn:absent"]) == []) assert(some_types_endpoint.match_types(types) == types) assert(some_types_endpoint.match_types([types[1], types[0]]) == types) assert(some_types_endpoint.match_types([types[0]]) == [types[0]]) assert(some_types_endpoint.match_types(types + ["urn:absent"]) == types) end def test_from_basic_service_endpoint # Check BasicServiceEndpoint.from_basic_service_endpoint endpoint = "unused" e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) assert(Yadis::BasicServiceEndpoint.from_basic_service_endpoint(endpoint) == endpoint) assert(e.from_basic_service_endpoint(endpoint) == endpoint) end end class TransformFilterMakerTest < Minitest::Test def make_service_element(types, uris) service = REXML::Element.new('Service') types.each { |type_text| service.add_element('Type').text = type_text } uris.each { |uri_text| service.add_element('URI').text = uri_text } return service end def test_get_service_endpoints yadis_url = "http://yad.is/" uri = "http://uri/" type_uris = ["urn:type1", "urn:type2"] element = make_service_element(type_uris, [uri]) filters = [Proc.new { |endpoint| if endpoint.service_element == element endpoint else nil end } ] tf = Yadis::TransformFilterMaker.new(filters) result = tf.get_service_endpoints(yadis_url, element) assert_equal(result[0].yadis_url, yadis_url, result) assert_equal(result[0].uri, uri, result) end def test_empty_transform_filter # A transform filter with no filter procs should return nil. endpoint = "unused" t = Yadis::TransformFilterMaker.new([]) assert(t.apply_filters(endpoint).nil?) end def test_nil_filter # A transform filter with a single nil filter should return nil. nil_filter = Proc.new { |endpoint| nil } t = Yadis::TransformFilterMaker.new([nil_filter]) endpoint = "unused" assert(t.apply_filters(endpoint).nil?) end def test_identity_filter # A transform filter with an identity filter should return the # input. identity_filter = Proc.new { |endpoint| endpoint } t = Yadis::TransformFilterMaker.new([identity_filter]) endpoint = "unused" assert(t.apply_filters(endpoint) == endpoint) end def test_return_different_endpoint # Make sure the result of the filter is returned, rather than # the input. returned_endpoint = "returned endpoint" filter = Proc.new { |endpoint| returned_endpoint } t = Yadis::TransformFilterMaker.new([filter]) endpoint = "unused" assert(t.apply_filters(endpoint) == returned_endpoint) end def test_multiple_filters # Check filter fallback behavior on different inputs. odd, odd_result = 45, "odd" even, even_result = 46, "even" filter_odd = Proc.new { |endpoint| if endpoint % 2 == 1 odd_result else nil end } filter_even = Proc.new { |endpoint| if endpoint % 2 == 0 even_result else nil end } t = Yadis::TransformFilterMaker.new([filter_odd, filter_even]) assert(t.apply_filters(odd) == odd_result) assert(t.apply_filters(even) == even_result) end end class BogusServiceEndpointExtractor def initialize(data) @data = data end def get_service_endpoints(yadis_url, service_element) return @data end end class CompoundFilterTest < Minitest::Test def test_get_service_endpoints first = ["bogus", "test"] second = ["third"] all = first + second subfilters = [ BogusServiceEndpointExtractor.new(first), BogusServiceEndpointExtractor.new(second), ] cf = Yadis::CompoundFilter.new(subfilters) assert cf.get_service_endpoints("unused", "unused") == all end end class MakeFilterTest < Minitest::Test def test_parts_nil result = Yadis.make_filter(nil) assert result.is_a?(Yadis::TransformFilterMaker) end def test_parts_array e1 = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) e2 = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) result = Yadis.make_filter([e1, e2]) assert result.is_a?(Yadis::TransformFilterMaker) assert result.filter_procs[0] == e1.method('from_basic_service_endpoint') assert result.filter_procs[1] == e2.method('from_basic_service_endpoint') end def test_parts_single e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) result = Yadis.make_filter(e) assert result.is_a?(Yadis::TransformFilterMaker) end end class MakeCompoundFilterTest < Minitest::Test def test_no_filters result = Yadis.mk_compound_filter([]) assert result.subfilters == [] end def test_single_transform_filter f = Yadis::TransformFilterMaker.new([]) assert_equal f, Yadis.mk_compound_filter([f]) end def test_single_endpoint e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) result = Yadis.mk_compound_filter([e]) assert result.is_a?(Yadis::TransformFilterMaker) # Expect the transform filter to call # from_basic_service_endpoint on the endpoint filter = result.filter_procs[0] assert_equal filter, e.method('from_basic_service_endpoint') end def test_single_proc # Create a proc that just returns nil for any endpoint p = Proc.new { |endpoint| nil } result = Yadis.mk_compound_filter([p]) assert result.is_a?(Yadis::TransformFilterMaker) # Expect the transform filter to call # from_basic_service_endpoint on the endpoint assert_equal result.filter_procs[0], p end def test_multiple_filters_same_type f1 = Yadis::TransformFilterMaker.new([]) f2 = Yadis::TransformFilterMaker.new([]) # Expect mk_compound_filter to actually make a CompoundFilter # from f1 and f2. result = Yadis.mk_compound_filter([f1, f2]) assert result.is_a?(Yadis::CompoundFilter) assert result.subfilters == [f1, f2] end def test_multiple_filters_different_type f1 = Yadis::TransformFilterMaker.new([]) f2 = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) f3 = Proc.new { |endpoint| nil } e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil) f4 = [e] # Expect mk_compound_filter to actually make a CompoundFilter # from f1 and f2. result = Yadis.mk_compound_filter([f1, f2, f3, f4]) assert result.is_a?(Yadis::CompoundFilter) assert result.subfilters[0] == f1 assert result.subfilters[1].filter_procs[0] == e.method('from_basic_service_endpoint') assert result.subfilters[2].filter_procs[0] == f2.method('from_basic_service_endpoint') assert result.subfilters[2].filter_procs[1] == f3 end def test_filter_type_error # Pass various non-filter objects and make sure the filter # machinery explodes. [nil, ["bogus"], [1], [nil, "bogus"]].each { |thing| assert_raises(TypeError) { Yadis.mk_compound_filter(thing) } } end end end ruby-openid-2.7.0debian.orig/test/test_extension.rb0000644000175000017500000000254012512544714021674 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/extension' require 'openid/message' module OpenID class DummyExtension < OpenID::Extension TEST_URI = 'http://an.extension' TEST_ALIAS = 'dummy' def initialize @ns_uri = TEST_URI @ns_alias = TEST_ALIAS end def get_extension_args return {} end end class ToMessageTest < Minitest::Test def test_OpenID1 oid1_msg = Message.new(OPENID1_NS) ext = DummyExtension.new ext.to_message(oid1_msg) namespaces = oid1_msg.namespaces assert(namespaces.implicit?(DummyExtension::TEST_URI)) assert_equal( DummyExtension::TEST_URI, namespaces.get_namespace_uri(DummyExtension::TEST_ALIAS)) assert_equal(DummyExtension::TEST_ALIAS, namespaces.get_alias(DummyExtension::TEST_URI)) end def test_OpenID2 oid2_msg = Message.new(OPENID2_NS) ext = DummyExtension.new ext.to_message(oid2_msg) namespaces = oid2_msg.namespaces assert(!namespaces.implicit?(DummyExtension::TEST_URI)) assert_equal( DummyExtension::TEST_URI, namespaces.get_namespace_uri(DummyExtension::TEST_ALIAS)) assert_equal(DummyExtension::TEST_ALIAS, namespaces.get_alias(DummyExtension::TEST_URI)) end end end ruby-openid-2.7.0debian.orig/test/test_discover.rb0000644000175000017500000005760112512544714021506 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'util' require 'openid/fetchers' require 'openid/yadis/discovery' require 'openid/consumer/discovery' require 'openid/yadis/xrires' require 'openid/yadis/xri' require 'openid/message' require 'openid/util' ### Tests for conditions that trigger DiscoveryFailure module OpenID class SimpleMockFetcher def initialize(test, responses) @test = test @responses = responses.dup end def fetch(url, body=nil, headers=nil, limit=nil) response = @responses.shift @test.assert(body.nil?) @test.assert_equal(response.final_url, url) return response end end class TestDiscoveryFailure < Minitest::Test def initialize(*args) super(*args) @responses = [ [HTTPResponse._from_raw_data(nil, nil, {}, 'http://network.error/')], [HTTPResponse._from_raw_data(404, nil, {}, 'http://not.found/')], [HTTPResponse._from_raw_data(400, nil, {}, 'http://bad.request/')], [HTTPResponse._from_raw_data(500, nil, {}, 'http://server.error/')], [HTTPResponse._from_raw_data(200, nil, {'x-xrds-location' => 'http://xrds.missing/'}, 'http://header.found/'), HTTPResponse._from_raw_data(404, nil, {}, 'http://xrds.missing/')], ] end def test_discovery_failure @responses.each { |response_set| @url = response_set[0].final_url OpenID.fetcher = SimpleMockFetcher.new(self, response_set) expected_status = response_set[-1].code begin OpenID.discover(@url) rescue DiscoveryFailure => why assert_equal(why.http_response.code, expected_status) else flunk('Did not raise DiscoveryFailure') end OpenID.fetcher = nil } end end ### Tests for raising/catching exceptions from the fetcher through ### the discover function class ErrorRaisingFetcher # Just raise an exception when fetch is called def initialize(thing_to_raise) @thing_to_raise = thing_to_raise end def fetch(url, body=nil, headers=nil, limit=nil) raise @thing_to_raise end end class DidFetch < Exception # Custom exception just to make sure it's not handled differently end class TestFetchException < Minitest::Test # Discovery should only raise DiscoveryFailure def initialize(*args) super(*args) @cases = [ DidFetch.new(), Exception.new(), ArgumentError.new(), RuntimeError.new(), ] end def test_fetch_exception @cases.each { |exc| OpenID.fetcher = ErrorRaisingFetcher.new(exc) assert_raises(DiscoveryFailure) { OpenID.discover('http://doesnt.matter/') } OpenID.fetcher = nil } end end ### Tests for openid.consumer.discover.discover class TestNormalization < Minitest::Test def test_addingProtocol f = ErrorRaisingFetcher.new(RuntimeError.new()) OpenID.fetcher = f begin OpenID.discover('users.stompy.janrain.com:8000/x') rescue DiscoveryFailure => why assert why.to_s.match("Failed to fetch") rescue RuntimeError end OpenID.fetcher = nil end end class DiscoveryMockFetcher def initialize(documents) @redirect = nil @documents = documents @fetchlog = [] end def fetch(url, body=nil, headers=nil, limit=nil) @fetchlog << [url, body, headers] if @redirect final_url = @redirect else final_url = url end begin ctype, body = @documents.fetch(url) rescue IndexError status = 404 ctype = 'text/plain' body = '' else status = 200 end return HTTPResponse._from_raw_data(status, body, {'content-type' => ctype}, final_url) end end class BaseTestDiscovery < Minitest::Test attr_accessor :id_url, :fetcher_class def initialize(*args) super(*args) @id_url = "http://someuser.unittest/" @documents = {} @fetcher_class = DiscoveryMockFetcher end def _checkService(s, server_url, claimed_id=nil, local_id=nil, canonical_id=nil, types=nil, used_yadis=false, display_identifier=nil) assert_equal(server_url, s.server_url) if types == ['2.0 OP'] assert(!claimed_id) assert(!local_id) assert(!s.claimed_id) assert(!s.local_id) assert(!s.get_local_id()) assert(!s.compatibility_mode()) assert(s.is_op_identifier()) assert_equal(s.preferred_namespace(), OPENID_2_0_MESSAGE_NS) else assert_equal(claimed_id, s.claimed_id) assert_equal(local_id, s.get_local_id()) end if used_yadis assert(s.used_yadis, "Expected to use Yadis") else assert(!s.used_yadis, "Expected to use old-style discovery") end openid_types = { '1.1' => OPENID_1_1_TYPE, '1.0' => OPENID_1_0_TYPE, '2.0' => OPENID_2_0_TYPE, '2.0 OP' => OPENID_IDP_2_0_TYPE, } type_uris = types.collect { |t| openid_types[t] } assert_equal(type_uris, s.type_uris) assert_equal(canonical_id, s.canonical_id) if canonical_id.nil? assert_equal(claimed_id, s.display_identifier) else assert_equal(display_identifier, s.display_identifier) end end def setup # @documents = @documents.dup @fetcher = @fetcher_class.new(@documents) OpenID.fetcher = @fetcher end def teardown OpenID.fetcher = nil end def test_blank # XXX to avoid > 0 test requirement end end # def readDataFile(filename): # module_directory = os.path.dirname(os.path.abspath(__file__)) # filename = os.path.join( # module_directory, 'data', 'test_discover', filename) # return file(filename).read() class TestDiscovery < BaseTestDiscovery include TestDataMixin def _discover(content_type, data, expected_services, expected_id=nil) if expected_id.nil? expected_id = @id_url end @documents[@id_url] = [content_type, data] id_url, services = OpenID.discover(@id_url) assert_equal(expected_services, services.length) assert_equal(expected_id, id_url) return services end def test_404 assert_raises(DiscoveryFailure) { OpenID.discover(@id_url + '/404') } end def test_noOpenID services = _discover('text/plain', "junk", 0) services = _discover( 'text/html', read_data_file('test_discover/openid_no_delegate.html', false), 1) _checkService( services[0], "http://www.myopenid.com/server", @id_url, @id_url, nil, ['1.1'], false) end def test_malformed_meta_tag @id_url = "http://user.myopenid.com/" services = _discover( 'text/html', read_data_file('test_discover/malformed_meta_tag.html', false), 2) _checkService( services[0], "http://www.myopenid.com/server", @id_url, @id_url, nil, ['2.0'], false) _checkService( services[1], "http://www.myopenid.com/server", @id_url, @id_url, nil, ['1.1'], false) end def test_html1 services = _discover('text/html', read_data_file('test_discover/openid.html', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, ['1.1'], false) end def test_html1Fragment # Ensure that the Claimed Identifier does not have a fragment if # one is supplied in the User Input. content_type = 'text/html' data = read_data_file('test_discover/openid.html', false) expected_services = 1 @documents[@id_url] = [content_type, data] expected_id = @id_url @id_url = @id_url + '#fragment' id_url, services = OpenID.discover(@id_url) assert_equal(expected_services, services.length) assert_equal(expected_id, id_url) _checkService(services[0], "http://www.myopenid.com/server", expected_id, 'http://smoker.myopenid.com/', nil, ['1.1'], false) end def test_html2 services = _discover('text/html', read_data_file('test_discover/openid2.html', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, ['2.0'], false) end def test_html1And2 services = _discover( 'text/html', read_data_file('test_discover/openid_1_and_2.html', false), 2) services.zip(['2.0', '1.1']).each { |s, t| _checkService(s, "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, [t], false) } end def test_html_utf8 utf8_html = read_data_file('test_discover/openid_utf8.html', false) utf8_html.force_encoding("UTF-8") if utf8_html.respond_to?(:force_encoding) services = _discover('text/html', utf8_html, 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, ['1.1'], false) end def test_yadisEmpty _discover('application/xrds+xml', read_data_file('test_discover/yadis_0entries.xml', false), 0) end def test_htmlEmptyYadis # HTML document has discovery information, but points to an # empty Yadis document. The XRDS document pointed to by # "openid_and_yadis.html" @documents[@id_url + 'xrds'] = ['application/xrds+xml', read_data_file('test_discover/yadis_0entries.xml', false)] services = _discover('text/html', read_data_file('test_discover/openid_and_yadis.html', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, ['1.1'], false) end def test_yadis1NoDelegate services = _discover('application/xrds+xml', read_data_file('test_discover/yadis_no_delegate.xml', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, @id_url, nil, ['1.0'], true) end def test_yadis2NoLocalID services = _discover('application/xrds+xml', read_data_file('test_discover/openid2_xrds_no_local_id.xml', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, @id_url, nil, ['2.0'], true) end def test_yadis2 services = _discover('application/xrds+xml', read_data_file('test_discover/openid2_xrds.xml', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, ['2.0'], true) end def test_yadis2OP services = _discover('application/xrds+xml', read_data_file('test_discover/yadis_idp.xml', false), 1) _checkService(services[0], "http://www.myopenid.com/server", nil, nil, nil, ['2.0 OP'], true) end def test_yadis2OPDelegate # The delegate tag isn't meaningful for OP entries. services = _discover('application/xrds+xml', read_data_file('test_discover/yadis_idp_delegate.xml', false), 1) _checkService(services[0], "http://www.myopenid.com/server", nil, nil, nil, ['2.0 OP'], true) end def test_yadis2BadLocalID assert_raises(DiscoveryFailure) { _discover('application/xrds+xml', read_data_file('test_discover/yadis_2_bad_local_id.xml', false), 1) } end def test_yadis1And2 services = _discover('application/xrds+xml', read_data_file('test_discover/openid_1_and_2_xrds.xml', false), 1) _checkService(services[0], "http://www.myopenid.com/server", @id_url, 'http://smoker.myopenid.com/', nil, ['2.0', '1.1'], true) end def test_yadis1And2BadLocalID assert_raises(DiscoveryFailure) { _discover('application/xrds+xml', read_data_file('test_discover/openid_1_and_2_xrds_bad_delegate.xml', false), 1) } end end class MockFetcherForXRIProxy def initialize(documents, proxy_url=Yadis::XRI::ProxyResolver::DEFAULT_PROXY) @documents = documents @fetchlog = [] @proxy_url = nil end def fetch(url, body=nil, headers=nil, limit=nil) @fetchlog << [url, body, headers] u = URI::parse(url) xri = u.path query = u.query if !headers and !query raise ArgumentError.new("No headers or query; you probably didn't " + "mean to do that.") end if xri.start_with?('/') xri = xri[1..-1] end begin ctype, body = @documents.fetch(xri) rescue IndexError status = 404 ctype = 'text/plain' body = '' else status = 200 end return HTTPResponse._from_raw_data(status, body, {'content-type' => ctype}, url) end end class TestXRIDiscovery < BaseTestDiscovery include TestDataMixin include TestUtil def initialize(*args) super(*args) @fetcher_class = MockFetcherForXRIProxy @documents = {'=smoker' => ['application/xrds+xml', read_data_file('test_discover/yadis_2entries_delegate.xml', false)], '=smoker*bad' => ['application/xrds+xml', read_data_file('test_discover/yadis_another_delegate.xml', false)]} end def test_xri _, services = OpenID.discover_xri('=smoker') _checkService(services[0], "http://www.myopenid.com/server", Yadis::XRI.make_xri("=!1000"), 'http://smoker.myopenid.com/', Yadis::XRI.make_xri("=!1000"), ['1.0'], true, '=smoker') _checkService(services[1], "http://www.livejournal.com/openid/server.bml", Yadis::XRI.make_xri("=!1000"), 'http://frank.livejournal.com/', Yadis::XRI.make_xri("=!1000"), ['1.0'], true, '=smoker') end def test_xri_normalize _, services = OpenID.discover_xri('xri://=smoker') _checkService(services[0], "http://www.myopenid.com/server", Yadis::XRI.make_xri("=!1000"), 'http://smoker.myopenid.com/', Yadis::XRI.make_xri("=!1000"), ['1.0'], true, '=smoker') _checkService(services[1], "http://www.livejournal.com/openid/server.bml", Yadis::XRI.make_xri("=!1000"), 'http://frank.livejournal.com/', Yadis::XRI.make_xri("=!1000"), ['1.0'], true, '=smoker') end def test_xriNoCanonicalID silence_logging { _, services = OpenID.discover_xri('=smoker*bad') assert(services.empty?) } end def test_useCanonicalID # When there is no delegate, the CanonicalID should be used with # XRI. endpoint = OpenIDServiceEndpoint.new() endpoint.claimed_id = Yadis::XRI.make_xri("=!1000") endpoint.canonical_id = Yadis::XRI.make_xri("=!1000") assert_equal(endpoint.get_local_id, Yadis::XRI.make_xri("=!1000")) end end class TestXRIDiscoveryIDP < BaseTestDiscovery include TestDataMixin def initialize(*args) super(*args) @fetcher_class = MockFetcherForXRIProxy @documents = {'=smoker' => ['application/xrds+xml', read_data_file('test_discover/yadis_2entries_idp.xml', false)] } end def test_xri _, services = OpenID.discover_xri('=smoker') assert(!services.empty?, "Expected services, got zero") assert_equal(services[0].server_url, "http://www.livejournal.com/openid/server.bml") end end class TestPreferredNamespace < Minitest::Test def initialize(*args) super(*args) @cases = [ [OPENID1_NS, []], [OPENID1_NS, ['http://jyte.com/']], [OPENID1_NS, [OPENID_1_0_TYPE]], [OPENID1_NS, [OPENID_1_1_TYPE]], [OPENID2_NS, [OPENID_2_0_TYPE]], [OPENID2_NS, [OPENID_IDP_2_0_TYPE]], [OPENID2_NS, [OPENID_2_0_TYPE, OPENID_1_0_TYPE]], [OPENID2_NS, [OPENID_1_0_TYPE, OPENID_2_0_TYPE]], ] end def test_preferred_namespace @cases.each { |expected_ns, type_uris| endpoint = OpenIDServiceEndpoint.new() endpoint.type_uris = type_uris actual_ns = endpoint.preferred_namespace() assert_equal(actual_ns, expected_ns) } end end class TestIsOPIdentifier < Minitest::Test def setup @endpoint = OpenIDServiceEndpoint.new() end def test_none assert(!@endpoint.is_op_identifier()) end def test_openid1_0 @endpoint.type_uris = [OPENID_1_0_TYPE] assert(!@endpoint.is_op_identifier()) end def test_openid1_1 @endpoint.type_uris = [OPENID_1_1_TYPE] assert(!@endpoint.is_op_identifier()) end def test_openid2 @endpoint.type_uris = [OPENID_2_0_TYPE] assert(!@endpoint.is_op_identifier()) end def test_openid2OP @endpoint.type_uris = [OPENID_IDP_2_0_TYPE] assert(@endpoint.is_op_identifier()) end def test_multipleMissing @endpoint.type_uris = [OPENID_2_0_TYPE, OPENID_1_0_TYPE] assert(!@endpoint.is_op_identifier()) end def test_multiplePresent @endpoint.type_uris = [OPENID_2_0_TYPE, OPENID_1_0_TYPE, OPENID_IDP_2_0_TYPE] assert(@endpoint.is_op_identifier()) end end class TestFromOPEndpointURL < Minitest::Test def setup @op_endpoint_url = 'http://example.com/op/endpoint' @endpoint = OpenIDServiceEndpoint.from_op_endpoint_url(@op_endpoint_url) end def test_isOPEndpoint assert(@endpoint.is_op_identifier()) end def test_noIdentifiers assert_equal(@endpoint.get_local_id, nil) assert_equal(@endpoint.claimed_id, nil) end def test_compatibility assert(!@endpoint.compatibility_mode()) end def test_canonical_id assert_equal(@endpoint.canonical_id, nil) end def test_serverURL assert_equal(@endpoint.server_url, @op_endpoint_url) end end class TestDiscoverFunction < Minitest::Test def test_discover_function # XXX these were all different tests in python, but they're # combined here so I only have to use with_method_overridden # once. discoverXRI = Proc.new { |identifier| 'XRI' } discoverURI = Proc.new { |identifier| 'URI' } OpenID.extend(OverrideMethodMixin) OpenID.with_method_overridden(:discover_uri, discoverURI) do OpenID.with_method_overridden(:discover_xri, discoverXRI) do assert_equal('URI', OpenID.discover('http://woo!')) assert_equal('URI', OpenID.discover('not a URL or XRI')) assert_equal('XRI', OpenID.discover('xri://=something')) assert_equal('XRI', OpenID.discover('=something')) end end end end class TestEndpointSupportsType < Minitest::Test def setup @endpoint = OpenIDServiceEndpoint.new() end def failUnlessSupportsOnly(*types) ['foo', OPENID_1_1_TYPE, OPENID_1_0_TYPE, OPENID_2_0_TYPE, OPENID_IDP_2_0_TYPE].each { |t| if types.member?(t) assert(@endpoint.supports_type(t), sprintf("Must support %s", t)) else assert(!@endpoint.supports_type(t), sprintf("Shouldn't support %s", t)) end } end def test_supportsNothing failUnlessSupportsOnly() end def test_openid2 @endpoint.type_uris = [OPENID_2_0_TYPE] failUnlessSupportsOnly(OPENID_2_0_TYPE) end def test_openid2provider @endpoint.type_uris = [OPENID_IDP_2_0_TYPE] failUnlessSupportsOnly(OPENID_IDP_2_0_TYPE, OPENID_2_0_TYPE) end def test_openid1_0 @endpoint.type_uris = [OPENID_1_0_TYPE] failUnlessSupportsOnly(OPENID_1_0_TYPE) end def test_openid1_1 @endpoint.type_uris = [OPENID_1_1_TYPE] failUnlessSupportsOnly(OPENID_1_1_TYPE) end def test_multiple @endpoint.type_uris = [OPENID_1_1_TYPE, OPENID_2_0_TYPE] failUnlessSupportsOnly(OPENID_1_1_TYPE, OPENID_2_0_TYPE) end def test_multipleWithProvider @endpoint.type_uris = [OPENID_1_1_TYPE, OPENID_2_0_TYPE, OPENID_IDP_2_0_TYPE] failUnlessSupportsOnly(OPENID_1_1_TYPE, OPENID_2_0_TYPE, OPENID_IDP_2_0_TYPE) end end class TestEndpointDisplayIdentifier < Minitest::Test def test_strip_fragment @endpoint = OpenIDServiceEndpoint.new() @endpoint.claimed_id = 'http://recycled.invalid/#123' assert_equal 'http://recycled.invalid/', @endpoint.display_identifier end end class TestNormalizeURL < Minitest::Test def test_no_host assert_raises(DiscoveryFailure) { OpenID::normalize_url('http:///too-many.invalid/slashes') } end end end ruby-openid-2.7.0debian.orig/test/test_urinorm.rb0000644000175000017500000000133512512544714021354 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "openid/urinorm" class URINormTestCase < Minitest::Test include OpenID::TestDataMixin def test_normalize lines = read_data_file('urinorm.txt') while lines.length > 0 case_name = lines.shift.strip actual = lines.shift.strip expected = lines.shift.strip lines.shift #=> newline if expected == 'fail' begin OpenID::URINorm.urinorm(actual) rescue URI::InvalidURIError assert true else raise 'Should have gotten URI error' end else normalized = OpenID::URINorm.urinorm(actual) assert_equal(expected, normalized, case_name) end end end end ruby-openid-2.7.0debian.orig/test/test_discovery_manager.rb0000644000175000017500000001752212512544714023367 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/consumer' require 'testutil' module OpenID class TestDiscoveredServices < Minitest::Test def setup @starting_url = "http://starting.url.com/" @yadis_url = "http://starting.url.com/xrds" @services = ["bogus", "not_a_service"] @disco_services = Consumer::DiscoveredServices.new(@starting_url, @yadis_url, @services.dup) end def test_next assert_equal(@disco_services.next, @services[0]) assert_equal(@disco_services.current, @services[0]) assert_equal(@disco_services.next, @services[1]) assert_equal(@disco_services.current, @services[1]) assert_equal(@disco_services.next, nil) assert_equal(@disco_services.current, nil) end def test_for_url assert(@disco_services.for_url?(@starting_url)) assert(@disco_services.for_url?(@yadis_url)) assert(!@disco_services.for_url?(nil)) assert(!@disco_services.for_url?("invalid")) end def test_started assert(!@disco_services.started?) @disco_services.next assert(@disco_services.started?) @disco_services.next assert(@disco_services.started?) @disco_services.next assert(!@disco_services.started?) end def test_empty assert(Consumer::DiscoveredServices.new(nil, nil, []).empty?) assert(!@disco_services.empty?) @disco_services.next @disco_services.next assert(@disco_services.started?) end end # I need to be able to test the protected methods; this lets me do # that. class PassthroughDiscoveryManager < Consumer::DiscoveryManager def method_missing(m, *args) method(m).call(*args) end end class TestDiscoveryManager < Minitest::Test def setup session = {} @session = OpenID::Consumer::Session.new(session, OpenID::Consumer::DiscoveredServices) @url = "http://unittest.com/" @key_suffix = "testing" @yadis_url = "http://unittest.com/xrds" @manager = PassthroughDiscoveryManager.new(session, @url, @key_suffix) @key = @manager.session_key end def test_construct # Make sure the default session key suffix is not nil. m = Consumer::DiscoveryManager.new(nil, nil) assert(!m.instance_variable_get("@session_key_suffix").nil?) m = Consumer::DiscoveryManager.new(nil, nil, "override") assert_equal(m.instance_variable_get("@session_key_suffix"), "override") end def test_get_next_service assert_equal(@session[@key], nil) next_service = @manager.get_next_service { [@yadis_url, ["one", "two", "three"]] } disco = @session[@key] assert_equal(disco.current, "one") assert_equal(next_service, "one") assert(disco.for_url?(@url)) assert(disco.for_url?(@yadis_url)) # The first two calls to get_next_service should return the # services in @disco. assert_equal(@manager.get_next_service, "two") assert_equal(@manager.get_next_service, "three") disco = @session[@key] assert_equal(disco.current, "three") # The manager is exhausted and should be deleted and a new one # should be created. @manager.get_next_service { [@yadis_url, ["four"]] } disco2 = @session[@key] assert_equal(disco2.current, "four") # create_manager may return a nil manager, in which case the # next service should be nil. @manager.extend(OpenID::InstanceDefExtension) @manager.instance_def(:create_manager) do |yadis_url, services| nil end result = @manager.get_next_service { |url| ["unused", []] } assert_equal(result, nil) end def test_cleanup # With no preexisting manager, cleanup() returns nil. assert_equal(@manager.cleanup, nil) # With a manager, it returns the manager's current service. disco = Consumer::DiscoveredServices.new(@url, @yadis_url, ["one", "two"]) @session[@key] = disco assert_equal(@manager.cleanup, nil) assert_equal(@session[@key], nil) disco.next @session[@key] = disco assert_equal(@manager.cleanup, "one") assert_equal(@session[@key], nil) # The force parameter should be passed through to get_manager # and destroy_manager. force_value = "yo" testcase = self m = Consumer::DiscoveredServices.new(nil, nil, ["inner"]) m.next @manager.extend(OpenID::InstanceDefExtension) @manager.instance_def(:get_manager) do |force| testcase.assert_equal(force, force_value) m end @manager.instance_def(:destroy_manager) do |force| testcase.assert_equal(force, force_value) end assert_equal("inner", @manager.cleanup(force_value)) end def test_get_manager # get_manager should always return the loaded manager when # forced. @session[@key] = "bogus" assert_equal("bogus", @manager.get_manager(true)) # When not forced, only managers for @url should be returned. disco = Consumer::DiscoveredServices.new(@url, @yadis_url, ["one"]) @session[@key] = disco assert_equal(@manager.get_manager, disco) # Try to get_manager for a manger that doesn't manage @url: disco2 = Consumer::DiscoveredServices.new("http://not.this.url.com/", "http://other.yadis.url/", ["one"]) @session[@key] = disco2 assert_equal(@manager.get_manager, nil) assert_equal(@manager.get_manager(true), disco2) end def test_create_manager assert(@session[@key].nil?) services = ["created", "manager"] returned_disco = @manager.create_manager(@yadis_url, services) stored_disco = @session[@key] assert_equal(stored_disco, returned_disco) assert(stored_disco.for_url?(@yadis_url)) assert_equal(stored_disco.next, "created") # Calling create_manager with a preexisting manager should # result in StandardError. assert_raises(StandardError) { @manager.create_manager(@yadis_url, services) } # create_manager should do nothing (and return nil) if given no # services. @session[@key] = nil result = @manager.create_manager(@yadis_url, []) assert(result.nil?) assert(@session[@key].nil?) end class DestroyCalledException < StandardError; end def test_destroy_manager # destroy_manager should remove the manager from the session, # forcibly if necessary. valid_disco = Consumer::DiscoveredServices.new(@url, @yadis_url, ["serv"]) invalid_disco = Consumer::DiscoveredServices.new("http://not.mine.com/", "http://different.url.com/", ["serv"]) @session[@key] = valid_disco @manager.destroy_manager assert(@session[@key].nil?) @session[@key] = invalid_disco @manager.destroy_manager assert_equal(@session[@key], invalid_disco) # Force destruction of manager, no matter which URLs it's for. @manager.destroy_manager(true) assert(@session[@key].nil?) end def test_session_key assert(@manager.session_key.end_with?( @manager.instance_variable_get("@session_key_suffix"))) end def test_store thing = "opaque" assert(@session[@key].nil?) @manager.store(thing) assert_equal(@session[@key], thing) end def test_load thing = "opaque" @session[@key] = thing assert_equal(@manager.load, thing) end def test_destroy! thing = "opaque" @manager.store(thing) assert_equal(@manager.load, thing) @manager.destroy! assert(@session[@key].nil?) assert(@manager.load.nil?) end end end ruby-openid-2.7.0debian.orig/test/test_responses.rb0000644000175000017500000000415312512544714021703 0ustar sbadiasbadiarequire "minitest/autorun" require "openid/consumer/discovery" require "openid/consumer/responses" module OpenID class Consumer module TestResponses class TestSuccessResponse < Minitest::Test def setup @endpoint = OpenIDServiceEndpoint.new @endpoint.claimed_id = 'identity_url' end def test_extension_response q = { 'ns.sreg' => 'urn:sreg', 'ns.unittest' => 'urn:unittest', 'unittest.one' => '1', 'unittest.two' => '2', 'sreg.nickname' => 'j3h', 'return_to' => 'return_to', } signed_list = q.keys.map { |k| 'openid.' + k } msg = Message.from_openid_args(q) resp = SuccessResponse.new(@endpoint, msg, signed_list) utargs = resp.extension_response('urn:unittest', false) assert_equal(utargs, {'one' => '1', 'two' => '2'}) sregargs = resp.extension_response('urn:sreg', false) assert_equal(sregargs, {'nickname' => 'j3h'}) end def test_extension_response_signed args = { 'ns.sreg' => 'urn:sreg', 'ns.unittest' => 'urn:unittest', 'unittest.one' => '1', 'unittest.two' => '2', 'sreg.nickname' => 'j3h', 'sreg.dob' => 'yesterday', 'return_to' => 'return_to', 'signed' => 'sreg.nickname,unittest.one,sreg.dob', } signed_list = ['openid.sreg.nickname', 'openid.unittest.one', 'openid.sreg.dob',] msg = Message.from_openid_args(args) resp = SuccessResponse.new(@endpoint, msg, signed_list) # All args in this NS are signed, so expect all. sregargs = resp.extension_response('urn:sreg', true) assert_equal(sregargs, {'nickname' => 'j3h', 'dob' => 'yesterday'}) # Not all args in this NS are signed, so expect nil when # asking for them. utargs = resp.extension_response('urn:unittest', true) assert_equal(nil, utargs) end end end end end ruby-openid-2.7.0debian.orig/test/test_ax.rb0000644000175000017500000006113712512544714020277 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/extensions/ax' require 'openid/message' require 'openid/consumer/responses' require 'openid/consumer/discovery' require 'openid/consumer/checkid_request' module OpenID module AX class BogusAXMessage < AXMessage @mode = 'bogus' def get_extension_args new_args end def do_check_mode(args) check_mode(args) end def do_check_mode_new_args check_mode(new_args) end end class AXMessageTest < Minitest::Test def setup @bax = BogusAXMessage.new end def test_check_mode assert_raises(Error) { @bax.do_check_mode({'mode' => 'fetch_request'})} @bax.do_check_mode({'mode' => @bax.mode}) end def test_check_mode_new_args @bax.do_check_mode_new_args end end class AttrInfoTest < Minitest::Test def test_construct assert_raises(ArgumentError) { AttrInfo.new } type_uri = 'uri geller' ainfo = AttrInfo.new(type_uri) assert_equal(type_uri, ainfo.type_uri) assert_equal(1, ainfo.count) assert_equal(false, ainfo.required) assert_equal(nil, ainfo.ns_alias) end end class ToTypeURIsTest < Minitest::Test def setup @aliases = NamespaceMap.new end def test_empty [nil, ''].each{|empty| uris = AX.to_type_uris(@aliases, empty) assert_equal([], uris) } end def test_undefined assert_raises(IndexError) { AX.to_type_uris(@aliases, 'http://janrain.com/') } end def test_one uri = 'http://janrain.com/' name = 'openid_hackers' @aliases.add_alias(uri, name) uris = AX::to_type_uris(@aliases, name) assert_equal([uri], uris) end def test_two uri1 = 'http://janrain.com/' name1 = 'openid_hackers' @aliases.add_alias(uri1, name1) uri2 = 'http://jyte.com/' name2 = 'openid_hack' @aliases.add_alias(uri2, name2) uris = AX.to_type_uris(@aliases, [name1, name2].join(',')) assert_equal([uri1, uri2], uris) end end class ParseAXValuesTest < Minitest::Test def ax_values(ax_args, expected_args) msg = KeyValueMessage.new msg.parse_extension_args(ax_args) assert_equal(expected_args, msg.data) end def ax_error(ax_args, error) msg = KeyValueMessage.new assert_raises(error) { msg.parse_extension_args(ax_args) } end def test_empty_is_valid ax_values({}, {}) end def test_missing_value_for_alias_explodes ax_error({'type.foo'=>'urn:foo'}, IndexError) end def test_count_present_but_not_value ax_error({'type.foo'=>'urn:foo', 'count.foo' => '1'}, IndexError) end def test_invalid_count_value msg = FetchRequest.new assert_raises(Error) { msg.parse_extension_args({'type.foo'=>'urn:foo', 'count.foo' => 'bogus'}) } end def test_request_unlimited_values msg = FetchRequest.new args = {'mode' => 'fetch_request', 'required' => 'foo', 'type.foo' => 'urn:foo', 'count.foo' => UNLIMITED_VALUES } msg.parse_extension_args(args) foo = msg.attributes[0] assert_equal(UNLIMITED_VALUES, foo.count) assert(foo.wants_unlimited_values?) end def test_long_alias # spec says we must support at least 32 character-long aliases name = 'x' * MINIMUM_SUPPORTED_ALIAS_LENGTH msg = KeyValueMessage.new args = { "type.#{name}" => 'urn:foo', "count.#{name}" => '1', "value.#{name}.1" => 'first', } msg.parse_extension_args(args) assert_equal(['first'],msg['urn:foo']) end def test_invalid_alias types = [ KeyValueMessage, FetchRequest ] inputs = [ {'type.a.b'=>'urn:foo', 'count.a.b'=>'1'}, {'type.a,b'=>'urn:foo', 'count.a,b'=>'1'}, ] types.each{|t| inputs.each{|input| msg = t.new assert_raises(Error) {msg.parse_extension_args(input)} } } end def test_count_present_and_is_zero ax_values( {'type.foo'=>'urn:foo', 'count.foo'=>'0', }, {'urn:foo'=>[]} ) end def test_singleton_empty ax_values( {'type.foo'=>'urn:foo', 'value.foo'=>'', }, {'urn:foo'=>[]} ) end def test_double_alias ax_error( {'type.foo'=>'urn:foo', 'value.foo'=>'', 'type.bar'=>'urn:foo', 'value.bar'=>'', }, IndexError ) end def test_double_singleton ax_values( {'type.foo'=>'urn:foo', 'value.foo'=>'', 'type.bar'=>'urn:bar', 'value.bar'=>'', }, {'urn:foo'=>[],'urn:bar'=>[]} ) end def singleton_value ax_values( {'type.foo'=>'urn:foo', 'value.foo'=>'something', }, {'urn:foo'=>['something']} ) end end class FetchRequestTest < Minitest::Test def setup @msg = FetchRequest.new @type_a = 'http://janrain.example.com/a' @name_a = 'a' end def test_mode assert_equal('fetch_request', @msg.mode) end def test_construct assert_equal({}, @msg.requested_attributes) assert_equal(nil, @msg.update_url) msg = FetchRequest.new('hailstorm') assert_equal({}, msg.requested_attributes) assert_equal('hailstorm', msg.update_url) end def test_add uri = 'mud://puddle' assert(! @msg.member?(uri)) a = AttrInfo.new(uri) @msg.add(a) assert(@msg.member?(uri)) end def test_add_twice uri = 'its://raining' a = AttrInfo.new(uri) @msg.add(a) assert_raises(IndexError) {@msg.add(a)} end def do_extension_args(expected_args) expected_args['mode'] = @msg.mode assert_equal(expected_args, @msg.get_extension_args) end def test_get_extension_args_empty do_extension_args({}) end def test_get_extension_args_no_alias a = AttrInfo.new('foo://bar') @msg.add(a) ax_args = @msg.get_extension_args ax_args.each{|k,v| if v == a.type_uri and k.index('type.') == 0 @name = k[5..-1] break end } do_extension_args({'type.'+@name => a.type_uri, 'if_available' => @name}) end def test_get_extension_args_alias_if_available a = AttrInfo.new('type://of.transportation', 'transport') @msg.add(a) do_extension_args({'type.'+a.ns_alias => a.type_uri, 'if_available' => a.ns_alias}) end def test_get_extension_args_alias_req a = AttrInfo.new('type://of.transportation', 'transport', true) @msg.add(a) do_extension_args({'type.'+a.ns_alias => a.type_uri, 'required' => a.ns_alias}) end def test_get_required_attrs_empty assert_equal([], @msg.get_required_attrs) end def test_parse_extension_args_extra_type args = { 'mode' => 'fetch_request', 'type.' + @name_a => @type_a } assert_raises(Error) {@msg.parse_extension_args(args)} end def test_parse_extension_args args = { 'mode' => 'fetch_request', 'type.' + @name_a => @type_a, 'if_available' => @name_a } @msg.parse_extension_args(args) assert(@msg.member?(@type_a) ) assert_equal([@type_a], @msg.requested_types) ai = @msg.requested_attributes[@type_a] assert(ai.is_a?(AttrInfo)) assert(!ai.required) assert_equal(@type_a, ai.type_uri) assert_equal(@name_a, ai.ns_alias) assert_equal([ai], @msg.attributes) end def test_extension_args_idempotent args = { 'mode' => 'fetch_request', 'type.' + @name_a => @type_a, 'if_available' => @name_a } @msg.parse_extension_args(args) assert_equal(args, @msg.get_extension_args) assert(!@msg.requested_attributes[@type_a].required) end def test_extension_args_idempotent_count_required args = { 'mode' => 'fetch_request', 'type.' + @name_a => @type_a, 'count.' + @name_a => '2', 'required' => @name_a } @msg.parse_extension_args(args) assert_equal(args, @msg.get_extension_args) assert(@msg.requested_attributes[@type_a].required) end def test_extension_args_count1 args = { 'mode' => 'fetch_request', 'type.' + @name_a => @type_a, 'count.' + @name_a => '1', 'if_available' => @name_a } norm_args = { 'mode' => 'fetch_request', 'type.' + @name_a => @type_a, 'if_available' => @name_a } @msg.parse_extension_args(args) assert_equal(norm_args, @msg.get_extension_args) end def test_from_openid_request_no_ax message = Message.new openid_req = Server::OpenIDRequest.new openid_req.message = message ax_req = FetchRequest.from_openid_request(openid_req) assert(ax_req.nil?) end def test_from_openid_request_wrong_ax_mode uri = 'http://under.the.sea/' name = 'ext0' value = 'snarfblat' message = OpenID::Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'store_request', 'ax.type.' + name => uri, 'ax.count.' + name => '1', 'ax.value.' + name + '.1' => value }) openid_req = Server::OpenIDRequest.new openid_req.message = message ax_req = FetchRequest.from_openid_request(openid_req) assert(ax_req.nil?) end def test_openid_update_url_verification_error openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'realm' => 'http://example.com/realm', 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://different.site/path', 'ax.mode' => 'fetch_request', }) openid_req = Server::OpenIDRequest.new openid_req.message = openid_req_msg assert_raises(Error) { FetchRequest.from_openid_request(openid_req) } end def test_openid_no_realm openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://different.site/path', 'ax.mode' => 'fetch_request', }) openid_req = Server::OpenIDRequest.new openid_req.message = openid_req_msg assert_raises(Error) { FetchRequest.from_openid_request(openid_req) } end def test_openid_update_url_verification_success openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'realm' => 'http://example.com/realm', 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'fetch_request', }) openid_req = Server::OpenIDRequest.new openid_req.message = openid_req_msg fr = FetchRequest.from_openid_request(openid_req) assert(fr.is_a?(FetchRequest)) end def test_openid_update_url_verification_success_return_to openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'return_to' => 'http://example.com/realm', 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'fetch_request', }) openid_req = Server::OpenIDRequest.new openid_req.message = openid_req_msg fr = FetchRequest.from_openid_request(openid_req) assert(fr.is_a?(FetchRequest)) end def test_add_extension openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'return_to' => 'http://example.com/realm', }) e = OpenID::OpenIDServiceEndpoint.new openid_req = Consumer::CheckIDRequest.new(nil, e) openid_req.message = openid_req_msg fr = FetchRequest.new fr.add(AttrInfo.new("urn:bogus")) openid_req.add_extension(fr) expected = { 'mode' => 'fetch_request', 'if_available' => 'ext0', 'type.ext0' => 'urn:bogus', } expected.each { |k,v| assert(openid_req.message.get_arg(AXMessage::NS_URI, k) == v) } end end class FetchResponseTest < Minitest::Test def setup @msg = FetchResponse.new @value_a = 'commodity' @value_a1 = 'value2' @type_a = 'http://blood.transfusion/' @name_a = 'george' @request_update_url = 'http://some.url.that.is.awesome/' end def test_construct assert_equal(nil, @msg.update_url) assert_equal({}, @msg.data) end def test_get_extension_args_empty eargs = { 'mode' => 'fetch_response' } assert_equal(eargs, @msg.get_extension_args) end def test_get_extension_args_empty_request eargs = { 'mode' => 'fetch_response' } req = FetchRequest.new assert_equal(eargs, @msg.get_extension_args(req)) end def test_get_extension_args_empty_request_some uri = 'http://not.found/' name = 'ext0' eargs = { 'mode' => 'fetch_response', 'type.' + name => uri, 'count.' + name => '0' } req = FetchRequest.new req.add(AttrInfo.new(uri)) assert_equal(eargs, @msg.get_extension_args(req)) end def test_update_url_in_response uri = 'http://not.found/' name = 'ext0' eargs = { 'mode' => 'fetch_response', 'update_url' => @request_update_url, 'type.' + name => uri, 'count.' + name => '0' } req = FetchRequest.new(@request_update_url) req.add(AttrInfo.new(uri)) assert_equal(eargs, @msg.get_extension_args(req)) end def test_get_extension_args_single_value_response # Single values do NOT have a count, and # do not use the array extension eargs = { 'mode' => 'fetch_response', 'type.' + @name_a => @type_a, 'value.' + @name_a => @value_a } req = FetchRequest.new req.add(AttrInfo.new(@type_a, @name_a)) @msg.add_value(@type_a, @value_a) assert_equal(eargs, @msg.get_extension_args(req)) end def test_get_extension_args_array_value_response # Multiple array values add the count, and array index # to each value eargs = { 'mode' => 'fetch_response', 'type.' + @name_a => @type_a, 'value.' + @name_a + ".1" => @value_a, 'value.' + @name_a + ".2" => @value_a1, 'count.' + @name_a => '2' } req = FetchRequest.new # Specify that this URI should have a count of 2 req.add(AttrInfo.new(@type_a, @name_a, true, 2)) # Push both values onto the array @msg.add_value(@type_a, @value_a) @msg.add_value(@type_a, @value_a1) assert_equal(eargs, @msg.get_extension_args(req)) end def test_get_extension_args_some_not_request req = FetchRequest.new @msg.add_value(@type_a, @value_a) assert_raises(IndexError) {@msg.get_extension_args(req)} end def test_get_single_success @msg.add_value(@type_a, @value_a) assert_equal(@value_a, @msg.get_single(@type_a)) end def test_get_single_none assert_equal(nil, @msg.get_single(@type_a)) end def test_get_single_extra @msg.set_values(@type_a, ['x', 'y']) assert_raises(Error) { @msg.get_single(@type_a) } end def test_from_unsigned_success_response uri = 'http://under.the.sea/' name = 'ext0' value = 'snarfblat' m = OpenID::Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'fetch_response', 'ax.type.' + name => uri, 'ax.count.' + name => '1', 'ax.value.' + name + '.1' => value }) e = OpenID::OpenIDServiceEndpoint.new() resp = OpenID::Consumer::SuccessResponse.new(e, m, []) ax_resp = FetchResponse.from_success_response(resp, false) values = ax_resp[uri] assert_equal(values, [value]) end def test_from_signed_success_response uri = 'http://under.the.sea/' name = 'ext0' value = 'snarfblat' oid_fields = { 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'fetch_response', 'ax.type.' + name => uri, 'ax.count.' + name => '1', 'ax.value.' + name + '.1' => value } signed_fields = oid_fields.keys.map{|f| "openid.#{f}"} m = OpenID::Message.from_openid_args(oid_fields) e = OpenID::OpenIDServiceEndpoint.new() resp = OpenID::Consumer::SuccessResponse.new(e, m, signed_fields) ax_resp = FetchResponse.from_success_response(resp, true) values = ax_resp[uri] assert_equal(values, [value]) end def test_from_signed_success_response_with_unsigned_attributes uri = 'http://under.the.sea/' name = 'ext0' value = 'snarfblat' m = OpenID::Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'fetch_response', 'ax.type.' + name => uri, 'ax.count.' + name => '1', 'ax.value.' + name + '.1' => value }) e = OpenID::OpenIDServiceEndpoint.new() resp = OpenID::Consumer::SuccessResponse.new(e, m, []) assert_nil FetchResponse.from_success_response(resp, true) end def test_from_empty_success_response e = OpenID::OpenIDServiceEndpoint.new() m = OpenID::Message.from_openid_args({'mode' => 'id_res'}) resp = OpenID::Consumer::SuccessResponse.new(e, m, []) ax_resp = FetchResponse.from_success_response(resp) assert(ax_resp.nil?) end end class StoreRequestTest < Minitest::Test def setup @msg = StoreRequest.new @type_a = 'http://oranges.are.for/' @name_a = 'juggling' end def test_construct assert_equal({}, @msg.data) end def test_get_extension_args_empty eargs = { 'mode' => 'store_request' } assert_equal(eargs, @msg.get_extension_args) end def test_from_openid_request_wrong_ax_mode uri = 'http://under.the.sea/' name = 'ext0' value = 'snarfblat' message = OpenID::Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.ax' => AXMessage::NS_URI, 'ax.update_url' => 'http://example.com/realm/update_path', 'ax.mode' => 'fetch_request', 'ax.type.' + name => uri, 'ax.count.' + name => '1', 'ax.value.' + name + '.1' => value }) openid_req = Server::OpenIDRequest.new openid_req.message = message ax_req = StoreRequest.from_openid_request(openid_req) assert(ax_req.nil?) end def test_get_extension_args_nonempty @msg.set_values(@type_a, ['foo','bar']) aliases = NamespaceMap.new aliases.add_alias(@type_a, @name_a) eargs = { 'mode' => 'store_request', 'type.' + @name_a => @type_a, 'value.' + @name_a + '.1' => 'foo', 'value.' + @name_a + '.2' => 'bar', 'count.' + @name_a => '2' } assert_equal(eargs, @msg.get_extension_args(aliases)) end end class StoreResponseTest < Minitest::Test def test_success msg = StoreResponse.new assert(msg.succeeded?) assert(!msg.error_message) assert_equal({'mode' => 'store_response_success'}, msg.get_extension_args) end def test_fail_nomsg msg = StoreResponse.new(false) assert(! msg.succeeded? ) assert(! msg.error_message ) assert_equal({'mode' => 'store_response_failure'}, msg.get_extension_args) end def test_fail_msg reason = "because I said so" msg = StoreResponse.new(false, reason) assert(! msg.succeeded? ) assert_equal(reason, msg.error_message) assert_equal({'mode' => 'store_response_failure', 'error' => reason}, msg.get_extension_args) end end end end ruby-openid-2.7.0debian.orig/test/test_checkid_request.rb0000644000175000017500000002240012512544714023017 0ustar sbadiasbadiarequire "minitest/autorun" require "openid/consumer/checkid_request" require "openid/message" require "testutil" require "util" module OpenID class Consumer class CheckIDRequest class DummyEndpoint attr_accessor :preferred_namespace, :local_id, :server_url, :is_op_identifier, :claimed_id def initialize @preferred_namespace = nil @local_id = nil @server_url = nil @is_op_identifier = false end def get_local_id @local_id end def compatibility_mode @preferred_namespace == OPENID1_NS end end module CheckIDTestMixin include TestUtil def setup @endpoint = DummyEndpoint.new @endpoint.local_id = 'http://server.unittest/joe' @endpoint.claimed_id = 'http://joe.vanity.example/' @endpoint.server_url = 'http://server.unittest/' @endpoint.preferred_namespace = preferred_namespace @realm = 'http://example/' @return_to = 'http://example/return/' @assoc = GoodAssoc.new @checkid_req = CheckIDRequest.new(@assoc, @endpoint) end def assert_has_identifiers(msg, local_id, claimed_id) assert_openid_value_equal(msg, 'identity', local_id) assert_openid_value_equal(msg, 'claimed_id', claimed_id) end def assert_openid_key_exists(msg, key) assert(msg.get_arg(OPENID_NS, key), "#{key} not present in #{msg.get_args(OPENID_NS).inspect}") end def assert_openid_key_absent(msg, key) assert(msg.get_arg(OPENID_NS, key).nil?) end def assert_openid_value_equal(msg, key, expected) actual = msg.get_arg(OPENID_NS, key, NO_DEFAULT) error_text = ("Expected #{expected.inspect} for openid.#{key} "\ "but got #{actual.inspect}: #{msg.inspect}") assert_equal(expected, actual, error_text) end def assert_anonymous(msg) ['claimed_id', 'identity'].each do |key| assert_openid_key_absent(msg, key) end end def assert_has_required_fields(msg) internal_message = @checkid_req.instance_variable_get(:@message) assert_equal(preferred_namespace, internal_message.get_openid_namespace) assert_equal(preferred_namespace, msg.get_openid_namespace) assert_openid_value_equal(msg, 'mode', expected_mode) # Implement these in subclasses because they depend on # protocol differences! assert_has_realm(msg) assert_identifiers_present(msg) end # TESTS def test_check_no_assoc_handle @checkid_req.instance_variable_set('@assoc', nil) msg = assert_log_matches("Generated checkid") { @checkid_req.get_message(@realm, @return_to, immediate) } assert_openid_key_absent(msg, 'assoc_handle') end def test_add_extension_arg @checkid_req.add_extension_arg('bag:', 'color', 'brown') @checkid_req.add_extension_arg('bag:', 'material', 'paper') assert(@checkid_req.message.namespaces.member?('bag:')) assert_equal(@checkid_req.message.get_args('bag:'), {'color' => 'brown', 'material' => 'paper'}) msg = assert_log_matches("Generated checkid") { @checkid_req.get_message(@realm, @return_to, immediate) } # XXX: this depends on the way that Message assigns # namespaces. Really it doesn't care that it has alias "0", # but that is tested anyway post_args = msg.to_post_args() assert_equal('brown', post_args['openid.ext0.color']) assert_equal('paper', post_args['openid.ext0.material']) end def test_standard msg = assert_log_matches('Generated checkid') { @checkid_req.get_message(@realm, @return_to, immediate) } assert_has_identifiers(msg, @endpoint.local_id, @endpoint.claimed_id) end def test_send_redirect? silence_logging { url = @checkid_req.redirect_url(@realm, @return_to, immediate) assert(url.length < OPENID1_URL_LIMIT) assert(@checkid_req.send_redirect?(@realm, @return_to, immediate)) @return_to << '/foo' * 1000 url = @checkid_req.redirect_url(@realm, @return_to, immediate) assert(url.length > OPENID1_URL_LIMIT) actual = @checkid_req.send_redirect?(@realm, @return_to, immediate) expected = preferred_namespace != OPENID2_NS assert_equal(expected, actual) } end end class TestCheckIDRequestOpenID2 < Minitest::Test include CheckIDTestMixin def immediate false end def expected_mode 'checkid_setup' end def preferred_namespace OPENID2_NS end # check presence of proper realm key and absence of the wrong # one. def assert_has_realm(msg) assert_openid_value_equal(msg, 'realm', @realm) assert_openid_key_absent(msg, 'trust_root') end def assert_identifiers_present(msg) identity_present = msg.has_key?(OPENID_NS, 'identity') claimed_present = msg.has_key?(OPENID_NS, 'claimed_id') assert_equal(claimed_present, identity_present) end # OpenID Checkid_Requests should be able to set 'anonymous' to true. def test_set_anonymous_works_for_openid2 assert(@checkid_req.message.is_openid2) @checkid_req.anonymous = true @checkid_req.anonymous = false end def test_user_anonymous_ignores_identfier @checkid_req.anonymous = true msg = assert_log_matches('Generated checkid') { @checkid_req.get_message(@realm, @return_to, immediate) } assert_has_required_fields(msg) assert_anonymous(msg) end def test_op_anonymous_ignores_identifier @endpoint.is_op_identifier = true @checkid_req.anonymous = true msg = assert_log_matches('Generated checkid') { @checkid_req.get_message(@realm, @return_to, immediate) } assert_has_required_fields(msg) assert_anonymous(msg) end def test_op_identifier_sends_identifier_select @endpoint.is_op_identifier = true msg = assert_log_matches('Generated checkid') { @checkid_req.get_message(@realm, @return_to, immediate) } assert_has_required_fields(msg) assert_has_identifiers(msg, IDENTIFIER_SELECT, IDENTIFIER_SELECT) end def test_no_assoc_handle msg = assert_log_matches("Generated checkid") { @checkid_req.get_message(@realm, @return_to, immediate) } assert_openid_key_absent(msg, 'assoc_handle') end end class TestCheckIDRequestOpenID1 < Minitest::Test include CheckIDTestMixin def immediate false end def preferred_namespace OPENID1_NS end def expected_mode 'checkid_setup' end # Make sure claimed_is is *absent* in request. def assert_has_identifiers(msg, op_specific_id, claimed_id) assert_openid_value_equal(msg, 'identity', op_specific_id) assert_openid_key_absent(msg, 'claimed_id') end def assert_identifiers_present(msg) assert_openid_key_absent(msg, 'claimed_id') assert(msg.has_key?(OPENID_NS, 'identity')) end # check presence of proper realm key and absence of the wrong # one. def assert_has_realm(msg) assert_openid_value_equal(msg, 'trust_root', @realm) assert_openid_key_absent(msg, 'realm') end # TESTS # OpenID 1 requests MUST NOT be able to set anonymous to true def test_set_anonymous_fails_for_openid1 assert(@checkid_req.message.is_openid1) assert_raises(ArgumentError) { @checkid_req.anonymous = true } @checkid_req.anonymous = false end # Identfier select SHOULD NOT be sent, but this pathway is in # here in case some special discovery stuff is done to trigger # it with OpenID 1. If it is triggered, it will send # identifier_select just like OpenID 2. def test_identifier_select @endpoint.is_op_identifier = true msg = assert_log_matches('Generated checkid') { @checkid_req.get_message(@realm, @return_to, immediate) } assert_has_required_fields(msg) assert_equal(IDENTIFIER_SELECT, msg.get_arg(OPENID1_NS, 'identity')) end end class TestCheckIDRequestOpenID1Immediate < TestCheckIDRequestOpenID1 def immediate true end def expected_mode 'checkid_immediate' end end class TestCheckid_RequestOpenID2Immediate < TestCheckIDRequestOpenID2 def immediate true end def expected_mode 'checkid_immediate' end end end end end ruby-openid-2.7.0debian.orig/test/test_association.rb0000644000175000017500000002200612512544714022173 0ustar sbadiasbadiarequire "minitest/autorun" require "openid/association" require "openid/protocolerror" module OpenID class AssociationTestCase < Minitest::Test def setup # Use this funny way of getting a time so that it does not have # fractional seconds, and so can be serialized exactly using our # standard code. issued = Time.at(Time.now.to_i) lifetime = 600 @assoc = Association.new('handle', 'secret', issued, lifetime, 'HMAC-SHA1') end def test_round_trip assoc2 = Association.deserialize(@assoc.serialize()) [:handle, :secret, :lifetime, :assoc_type].each do |attr| assert_equal(@assoc.send(attr), assoc2.send(attr)) end end def test_deserialize_failure field_list = Util.kv_to_seq(@assoc.serialize) kv = Util.seq_to_kv(field_list + [['monkeys', 'funny']]) assert_raises(ProtocolError) { Association.deserialize(kv) } bad_version_list = field_list.dup bad_version_list[0] = ['version', 'moon'] bad_version_kv = Util.seq_to_kv(bad_version_list) assert_raises(ProtocolError) { Association.deserialize(bad_version_kv) } end def test_serialization_identity assoc2 = Association.deserialize(@assoc.serialize) assert_equal(@assoc, assoc2) end def test_expires_in # Allow one second of slop assert(@assoc.expires_in.between?(599,600)) assert(@assoc.expires_in(Time.now.to_i).between?(599,600)) assert_equal(0,@assoc.expires_in(Time.now.to_i + 10000),"negative expires_in") end def test_from_expires_in start_time = Time.now expires_in = @assoc.expires_in assoc = Association.from_expires_in(expires_in, @assoc.handle, @assoc.secret, @assoc.assoc_type) # Allow one second of slop here for code execution time assert_in_delta(1, assoc.expires_in, @assoc.expires_in) [:handle, :secret, :assoc_type].each do |attr| assert_equal(@assoc.send(attr), assoc.send(attr)) end # Make sure the issued time is near the start assert(assoc.issued >= start_time) assert_in_delta(1, assoc.issued.to_f, start_time.to_f) end def test_sign_sha1 pairs = [['key1', 'value1'], ['key2', 'value2']] [['HMAC-SHA256', "\xfd\xaa\xfe;\xac\xfc*\x988\xad\x05d6-\xeaVy\xd5\xa5Z.<\xa9\xed\x18\x82\\$\x95x\x1c&"], ['HMAC-SHA1', "\xe0\x1bv\x04\xf1G\xc0\xbb\x7f\x9a\x8b\xe9\xbc\xee}\\\xe5\xbb7*"], ].each do |assoc_type, expected| assoc = Association.from_expires_in(3600, "handle", 'very_secret', assoc_type) sig = assoc.sign(pairs) assert_equal(expected.force_encoding("UTF-8"), sig.force_encoding("UTF-8")) m = Message.new(OPENID2_NS) pairs.each { |k, v| m.set_arg(OPENID_NS, k, v) } m.set_arg(BARE_NS, "not_an_openid_arg", "bogus") signed_m = assoc.sign_message(m) assert(signed_m.has_key?(OPENID_NS, 'sig')) assert_equal(signed_m.get_arg(OPENID_NS, 'signed'), 'assoc_handle,key1,key2,ns,signed') end end def test_sign_message_with_sig assoc = Association.from_expires_in(3600, "handle", "very_secret", "HMAC-SHA1") m = Message.new(OPENID2_NS) m.set_arg(OPENID_NS, 'sig', 'noise') assert_raises(ArgumentError) { assoc.sign_message(m) } end def test_sign_message_with_signed assoc = Association.from_expires_in(3600, "handle", "very_secret", "HMAC-SHA1") m = Message.new(OPENID2_NS) m.set_arg(OPENID_NS, 'signed', 'fields') assert_raises(ArgumentError) { assoc.sign_message(m) } end def test_sign_different_assoc_handle assoc = Association.from_expires_in(3600, "handle", "very_secret", "HMAC-SHA1") m = Message.new(OPENID2_NS) m.set_arg(OPENID_NS, 'assoc_handle', 'different') assert_raises(ArgumentError) { assoc.sign_message(m) } end def test_sign_bad_assoc_type @assoc.instance_eval { @assoc_type = 'Cookies' } assert_raises(ProtocolError) { @assoc.sign([]) } end def test_make_pairs msg = Message.new(OPENID2_NS) msg.update_args(OPENID2_NS, { 'mode' => 'id_res', 'identifier' => '=example', 'signed' => 'identifier,mode', 'sig' => 'cephalopod', }) msg.update_args(BARE_NS, {'xey' => 'value'}) assoc = Association.from_expires_in(3600, '{sha1}', 'very_secret', "HMAC-SHA1") pairs = assoc.make_pairs(msg) assert_equal([['identifier', '=example'], ['mode', 'id_res']], pairs) end def test_check_message_signature_no_signed m = Message.new(OPENID2_NS) m.update_args(OPENID2_NS, {'mode' => 'id_res', 'identifier' => '=example', 'sig' => 'coyote', }) assoc = Association.from_expires_in(3600, '{sha1}', 'very_secret', "HMAC-SHA1") assert_raises(ProtocolError) { assoc.check_message_signature(m) } end def test_check_message_signature_no_sig m = Message.new(OPENID2_NS) m.update_args(OPENID2_NS, {'mode' => 'id_res', 'identifier' => '=example', 'signed' => 'mode', }) assoc = Association.from_expires_in(3600, '{sha1}', 'very_secret', "HMAC-SHA1") assert_raises(ProtocolError) { assoc.check_message_signature(m) } end def test_check_message_signature_bad_sig m = Message.new(OPENID2_NS) m.update_args(OPENID2_NS, {'mode' => 'id_res', 'identifier' => '=example', 'signed' => 'mode', 'sig' => Util.to_base64('coyote'), }) assoc = Association.from_expires_in(3600, '{sha1}', 'very_secret', "HMAC-SHA1") assert(!assoc.check_message_signature(m)) end def test_check_message_signature_good_sig m = Message.new(OPENID2_NS) m.update_args(OPENID2_NS, {'mode' => 'id_res', 'identifier' => '=example', 'signed' => 'mode', 'sig' => Util.to_base64('coyote'), }) assoc = Association.from_expires_in(3600, '{sha1}', 'very_secret', "HMAC-SHA1") class << assoc # Override sign, because it's already tested elsewhere def sign(pairs) "coyote" end end assert(assoc.check_message_signature(m)) end end class AssociationNegotiatorTestCase < Minitest::Test def assert_equal_under(item1, item2) val1 = yield(item1) val2 = yield(item2) assert_equal(val1, val2) end def test_copy neg = AssociationNegotiator.new([['HMAC-SHA1', 'DH-SHA1']]) neg2 = neg.copy assert_equal_under(neg, neg2) {|n| n.instance_eval{@allowed_types} } assert(neg.object_id != neg2.object_id) end def test_add_allowed neg = AssociationNegotiator.new([]) assert(!neg.allowed?('HMAC-SHA1', 'DH-SHA1')) assert(!neg.allowed?('HMAC-SHA1', 'no-encryption')) assert(!neg.allowed?('HMAC-SHA256', 'DH-SHA256')) assert(!neg.allowed?('HMAC-SHA256', 'no-encryption')) neg.add_allowed_type('HMAC-SHA1') assert(neg.allowed?('HMAC-SHA1', 'DH-SHA1')) assert(neg.allowed?('HMAC-SHA1', 'no-encryption')) assert(!neg.allowed?('HMAC-SHA256', 'DH-SHA256')) assert(!neg.allowed?('HMAC-SHA256', 'no-encryption')) neg.add_allowed_type('HMAC-SHA256', 'DH-SHA256') assert(neg.allowed?('HMAC-SHA1', 'DH-SHA1')) assert(neg.allowed?('HMAC-SHA1', 'no-encryption')) assert(neg.allowed?('HMAC-SHA256', 'DH-SHA256')) assert(!neg.allowed?('HMAC-SHA256', 'no-encryption')) assert_equal(neg.get_allowed_type, ['HMAC-SHA1', 'DH-SHA1']) end def test_bad_assoc_type assert_raises(ProtocolError) { AssociationNegotiator.new([['OMG', 'Ponies']]) } end def test_bad_session_type assert_raises(ProtocolError) { AssociationNegotiator.new([['HMAC-SHA1', 'OMG-Ponies']]) } end def test_default_negotiator assert_equal(DefaultNegotiator.get_allowed_type, ['HMAC-SHA1', 'DH-SHA1']) assert(DefaultNegotiator.allowed?('HMAC-SHA256', 'no-encryption')) end def test_encrypted_negotiator assert_equal(EncryptedNegotiator.get_allowed_type, ['HMAC-SHA1', 'DH-SHA1']) assert(!EncryptedNegotiator.allowed?('HMAC-SHA256', 'no-encryption')) end end end ruby-openid-2.7.0debian.orig/test/test_idres.rb0000644000175000017500000010056412512544714020773 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "util" require "openid/consumer/idres" require "openid/protocolerror" require "openid/store/memory" require "openid/store/nonce" module OpenID class Consumer class IdResHandler # Subclass of IdResHandler that doesn't do verification upon # construction. All of the tests call this, except for the ones # explicitly for id_res. class IdResHandler < OpenID::Consumer::IdResHandler def id_res end end class CheckForFieldsTest < Minitest::Test include ProtocolErrorMixin BASE_FIELDS = ['return_to', 'assoc_handle', 'sig', 'signed'] OPENID2_FIELDS = BASE_FIELDS + ['op_endpoint'] OPENID1_FIELDS = BASE_FIELDS + ['identity'] OPENID1_SIGNED = ['return_to', 'identity'] OPENID2_SIGNED = OPENID1_SIGNED + ['response_nonce', 'claimed_id', 'assoc_handle', 'op_endpoint'] def mkMsg(ns, fields, signed_fields) msg = Message.new(ns) fields.each do |field| msg.set_arg(OPENID_NS, field, "don't care") end if fields.member?('signed') msg.set_arg(OPENID_NS, 'signed', signed_fields.join(',')) end msg end 1.times do # so as not to bleed into the outer namespace n = 0 [[], ['foo'], ['bar', 'baz'], ].each do |signed_fields| test = lambda do msg = mkMsg(OPENID2_NS, OPENID2_FIELDS, signed_fields) idres = IdResHandler.new(msg, nil) assert_equal(signed_fields, idres.send(:signed_list)) # Do it again to make sure logic for caching is correct assert_equal(signed_fields, idres.send(:signed_list)) end define_method("test_signed_list_#{n += 1}", test) end end # test all missing fields for OpenID 1 and 2 1.times do [["openid1", OPENID1_NS, OPENID1_FIELDS], ["openid1", OPENID11_NS, OPENID1_FIELDS], ["openid2", OPENID2_NS, OPENID2_FIELDS], ].each_with_index do |(ver, ns, all_fields), i| all_fields.each do |field| test = lambda do fields = all_fields.dup fields.delete(field) msg = mkMsg(ns, fields, []) idres = IdResHandler.new(msg, nil) assert_protocol_error("Missing required field #{field}") { idres.send(:check_for_fields) } end define_method("test_#{i}_#{ver}_check_missing_#{field}", test) end end end # Test all missing signed for OpenID 1 and 2 1.times do [["openid1", OPENID1_NS, OPENID1_FIELDS, OPENID1_SIGNED], ["openid1", OPENID11_NS, OPENID1_FIELDS, OPENID1_SIGNED], ["openid2", OPENID2_NS, OPENID2_FIELDS, OPENID2_SIGNED], ].each_with_index do |(ver, ns, all_fields, signed_fields), i| signed_fields.each do |signed_field| test = lambda do fields = signed_fields.dup fields.delete(signed_field) msg = mkMsg(ns, all_fields, fields) # Make sure the signed field is actually in the request msg.set_arg(OPENID_NS, signed_field, "don't care") idres = IdResHandler.new(msg, nil) assert_protocol_error("#{signed_field.inspect} not signed") { idres.send(:check_for_fields) } end define_method("test_#{i}_#{ver}_check_missing_signed_#{signed_field}", test) end end end def test_112 args = {'openid.assoc_handle' => 'fa1f5ff0-cde4-11dc-a183-3714bfd55ca8', 'openid.claimed_id' => 'http://binkley.lan/user/test01', 'openid.identity' => 'http://test01.binkley.lan/', 'openid.mode' => 'id_res', 'openid.ns' => 'http://specs.openid.net/auth/2.0', 'openid.ns.pape' => 'http://specs.openid.net/extensions/pape/1.0', 'openid.op_endpoint' => 'http://binkley.lan/server', 'openid.pape.auth_policies' => 'none', 'openid.pape.auth_time' => '2008-01-28T20:42:36Z', 'openid.pape.nist_auth_level' => '0', 'openid.response_nonce' => '2008-01-28T21:07:04Z99Q=', 'openid.return_to' => 'http://binkley.lan:8001/process?janrain_nonce=2008-01-28T21%3A07%3A02Z0tMIKx', 'openid.sig' => 'YJlWH4U6SroB1HoPkmEKx9AyGGg=', 'openid.signed' => 'assoc_handle,identity,response_nonce,return_to,claimed_id,op_endpoint,pape.auth_time,ns.pape,pape.nist_auth_level,pape.auth_policies' } assert_equal(args['openid.ns'], OPENID2_NS) incoming = Message.from_post_args(args) assert(incoming.is_openid2) idres = IdResHandler.new(incoming, nil) car = idres.send(:create_check_auth_request) expected_args = args.dup expected_args['openid.mode'] = 'check_authentication' expected = Message.from_post_args(expected_args) assert(expected.is_openid2) assert_equal(expected, car) assert_equal(expected_args, car.to_post_args) end def test_no_signed_list msg = Message.new(OPENID2_NS) idres = IdResHandler.new(msg, nil) assert_protocol_error("Response missing signed") { idres.send(:signed_list) } end def test_success_openid1 msg = mkMsg(OPENID1_NS, OPENID1_FIELDS, OPENID1_SIGNED) idres = IdResHandler.new(msg, nil) idres.send(:check_for_fields) end def test_success_openid1_1 msg = mkMsg(OPENID11_NS, OPENID1_FIELDS, OPENID1_SIGNED) idres = IdResHandler.new(msg, nil) idres.send(:check_for_fields) end end class ReturnToArgsTest < Minitest::Test include OpenID::ProtocolErrorMixin def check_return_to_args(query) idres = IdResHandler.new(Message.from_post_args(query), nil) class << idres def verify_return_to_base(unused) end end idres.send(:verify_return_to) end def assert_bad_args(msg, query) assert_protocol_error(msg) { check_return_to_args(query) } end def test_return_to_args_okay check_return_to_args({ 'openid.mode' => 'id_res', 'openid.return_to' => 'http://example.com/?foo=bar', 'foo' => 'bar', }) end def test_unexpected_arg_okay assert_bad_args("Unexpected parameter", { 'openid.mode' => 'id_res', 'openid.return_to' => 'http://example.com/', 'foo' => 'bar', }) end def test_return_to_mismatch assert_bad_args('Message missing ret', { 'openid.mode' => 'id_res', 'openid.return_to' => 'http://example.com/?foo=bar', }) assert_bad_args("Parameter 'foo' val", { 'openid.mode' => 'id_res', 'openid.return_to' => 'http://example.com/?foo=bar', 'foo' => 'foos', }) end end class ReturnToVerifyTest < Minitest::Test def test_bad_return_to return_to = "http://some.url/path?foo=bar" m = Message.new(OPENID1_NS) m.set_arg(OPENID_NS, 'mode', 'cancel') m.set_arg(BARE_NS, 'foo', 'bar') # Scheme, authority, and path differences are checked by # IdResHandler.verify_return_to_base. Query args checked by # IdResHandler.verify_return_to_args. [ # Scheme only "https://some.url/path?foo=bar", # Authority only "http://some.url.invalid/path?foo=bar", # Path only "http://some.url/path_extra?foo=bar", # Query args differ "http://some.url/path?foo=bar2", "http://some.url/path?foo2=bar", ].each do |bad| m.set_arg(OPENID_NS, 'return_to', bad) idres = IdResHandler.new(m, return_to) assert_raises(ProtocolError) { idres.send(:verify_return_to) } end end def test_good_return_to base = 'http://example.janrain.com/path' [ [base, {}], [base + "?another=arg", {'another' => 'arg'}], [base + "?another=arg#frag", {'another' => 'arg'}], ['HTTP'+base[4..-1], {}], [base.sub('com', 'COM'), {}], ['http://example.janrain.com:80/path', {}], ['http://example.janrain.com/p%61th', {}], ['http://example.janrain.com/./path',{}], ].each do |return_to, args| args['openid.return_to'] = return_to msg = Message.from_post_args(args) idres = IdResHandler.new(msg, base) idres.send(:verify_return_to) end end end class DummyEndpoint attr_accessor :server_url def initialize(server_url) @server_url = server_url end end class CheckSigTest < Minitest::Test include ProtocolErrorMixin include TestUtil def setup @assoc = GoodAssoc.new('{not_dumb}') @store = Store::Memory.new @server_url = 'http://server.url/' @endpoint = DummyEndpoint.new(@server_url) @store.store_association(@server_url, @assoc) @message = Message.from_post_args({ 'openid.mode' => 'id_res', 'openid.identity' => '=example', 'openid.sig' => GOODSIG, 'openid.assoc_handle' => @assoc.handle, 'openid.signed' => 'mode,identity,assoc_handle,signed', 'frobboz' => 'banzit', }) end def call_idres_method(method_name) idres = IdResHandler.new(@message, nil, @store, @endpoint) idres.extend(InstanceDefExtension) yield idres idres.send(method_name) end def call_check_sig(&proc) call_idres_method(:check_signature, &proc) end def no_check_auth(idres) idres.instance_def(:check_auth) { fail "Called check_auth" } end def test_sign_good call_check_sig(&method(:no_check_auth)) end def test_bad_sig @message.set_arg(OPENID_NS, 'sig', 'bad sig!') assert_protocol_error('Bad signature') { call_check_sig(&method(:no_check_auth)) } end def test_check_auth_ok @message.set_arg(OPENID_NS, 'assoc_handle', 'dumb-handle') check_auth_called = false call_check_sig do |idres| idres.instance_def(:check_auth) do check_auth_called = true end end assert(check_auth_called) end def test_check_auth_ok_no_store @store = nil check_auth_called = false call_check_sig do |idres| idres.instance_def(:check_auth) do check_auth_called = true end end assert(check_auth_called) end def test_expired_assoc @assoc.expires_in = -1 @store.store_association(@server_url, @assoc) assert_protocol_error('Association with') { call_check_sig(&method(:no_check_auth)) } end def call_check_auth(&proc) assert_log_matches("Using 'check_authentication'") { call_idres_method(:check_auth, &proc) } end def test_check_auth_create_fail assert_protocol_error("Could not generate") { call_check_auth do |idres| idres.instance_def(:create_check_auth_request) do raise Message::KeyNotFound, "Testing" end end } end def test_check_auth_okay OpenID.extend(OverrideMethodMixin) me = self send_resp = Proc.new do |req, server_url| me.assert_equal(:req, req) :expected_response end OpenID.with_method_overridden(:make_kv_post, send_resp) do call_check_auth do |idres| idres.instance_def(:create_check_auth_request) { :req } idres.instance_def(:process_check_auth_response) do |resp| me.assert_equal(:expected_response, resp) end end end end def test_check_auth_process_fail OpenID.extend(OverrideMethodMixin) me = self send_resp = Proc.new do |req, server_url| me.assert_equal(:req, req) :expected_response end OpenID.with_method_overridden(:make_kv_post, send_resp) do assert_protocol_error("Testing") do call_check_auth do |idres| idres.instance_def(:create_check_auth_request) { :req } idres.instance_def(:process_check_auth_response) do |resp| me.assert_equal(:expected_response, resp) raise ProtocolError, "Testing" end end end end end 1.times do # Fields from the signed list ['mode', 'identity', 'assoc_handle' ].each do |field| test = lambda do @message.del_arg(OPENID_NS, field) assert_raises(Message::KeyNotFound) { call_idres_method(:create_check_auth_request) {} } end define_method("test_create_check_auth_missing_#{field}", test) end end def test_create_check_auth_request_success ca_msg = call_idres_method(:create_check_auth_request) {} expected = @message.copy expected.set_arg(OPENID_NS, 'mode', 'check_authentication') assert_equal(expected, ca_msg) end end class CheckAuthResponseTest < Minitest::Test include TestUtil include ProtocolErrorMixin def setup @message = Message.from_openid_args({ 'is_valid' => 'true', }) @assoc = GoodAssoc.new @store = Store::Memory.new @server_url = 'http://invalid/' @endpoint = DummyEndpoint.new(@server_url) @idres = IdResHandler.new(nil, nil, @store, @endpoint) end def call_process @idres.send(:process_check_auth_response, @message) end def test_valid assert_log_matches() { call_process } end def test_invalid ['false', 'monkeys'].each do @message.set_arg(OPENID_NS, 'is_valid', 'false') assert_protocol_error("Server #{@server_url} responds") { assert_log_matches() { call_process } } end end def test_valid_invalidate @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese') assert_log_matches("Received 'invalidate_handle'") { call_process } end def test_invalid_invalidate @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese') ['false', 'monkeys'].each do @message.set_arg(OPENID_NS, 'is_valid', 'false') assert_protocol_error("Server #{@server_url} responds") { assert_log_matches("Received 'invalidate_handle'") { call_process } } end end def test_invalidate_no_store @idres.instance_variable_set(:@store, nil) @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese') assert_log_matches("Received 'invalidate_handle'", 'Unexpectedly got "invalidate_handle"') { call_process } end end class NonceTest < Minitest::Test include TestUtil include ProtocolErrorMixin def setup @store = Object.new class << @store attr_accessor :nonces, :succeed def use_nonce(server_url, time, extra) @nonces << [server_url, time, extra] @succeed end end @store.nonces = [] @nonce = Nonce.mk_nonce end def call_check_nonce(post_args, succeed=false) response = Message.from_post_args(post_args) if !@store.nil? @store.succeed = succeed end idres = IdResHandler.new(response, nil, @store, nil) idres.send(:check_nonce) end def test_openid1_success [{}, {'openid.ns' => OPENID1_NS}, {'openid.ns' => OPENID11_NS} ].each do |args| call_check_nonce({'rp_nonce' => @nonce}.merge(args), true) end end def test_openid1_missing [{}, {'openid.ns' => OPENID1_NS}, {'openid.ns' => OPENID11_NS} ].each do |args| assert_protocol_error('Nonce missing') { call_check_nonce(args) } end end def test_openid2_ignore_rp_nonce assert_protocol_error('Nonce missing') { call_check_nonce({'rp_nonce' => @nonce, 'openid.ns' => OPENID2_NS}) } end def test_openid2_success call_check_nonce({'openid.response_nonce' => @nonce, 'openid.ns' => OPENID2_NS}, true) end def test_openid1_ignore_response_nonce [{}, {'openid.ns' => OPENID1_NS}, {'openid.ns' => OPENID11_NS} ].each do |args| assert_protocol_error('Nonce missing') { call_check_nonce({'openid.response_nonce' => @nonce}.merge(args)) } end end def test_no_store @store = nil call_check_nonce({'rp_nonce' => @nonce}) end def test_already_used assert_protocol_error('Nonce already used') { call_check_nonce({'rp_nonce' => @nonce}, false) } end def test_malformed_nonce assert_protocol_error('Malformed nonce') { call_check_nonce({'rp_nonce' => 'whee!'}) } end end class DiscoveryVerificationTest < Minitest::Test include ProtocolErrorMixin include TestUtil def setup @endpoint = OpenIDServiceEndpoint.new end def call_verify(msg_args) call_verify_modify(msg_args){} end def call_verify_modify(msg_args) msg = Message.from_openid_args(msg_args) idres = IdResHandler.new(msg, nil, nil, @endpoint) idres.extend(InstanceDefExtension) yield idres idres.send(:verify_discovery_results) idres.instance_variable_get(:@endpoint) end def assert_verify_protocol_error(error_prefix, openid_args) assert_protocol_error(error_prefix) {call_verify(openid_args)} end def test_openid1_no_local_id @endpoint.claimed_id = 'http://invalid/' assert_verify_protocol_error("Missing required field: "\ "<#{OPENID1_NS}>identity", {}) end def test_openid1_no_endpoint @endpoint = nil assert_raises(ProtocolError) { call_verify({'identity' => 'snakes on a plane'}) } end def test_openid1_fallback_1_0 [OPENID1_NS, OPENID11_NS].each do |openid1_ns| claimed_id = 'http://claimed.id/' @endpoint = nil resp_mesg = Message.from_openid_args({ 'ns' => openid1_ns, 'identity' => claimed_id, }) # Pass the OpenID 1 claimed_id this way since we're # passing None for the endpoint. resp_mesg.set_arg(BARE_NS, 'openid1_claimed_id', claimed_id) # We expect the OpenID 1 discovery verification to try # matching the discovered endpoint against the 1.1 type # and fall back to 1.0. expected_endpoint = OpenIDServiceEndpoint.new expected_endpoint.type_uris = [OPENID_1_0_TYPE] expected_endpoint.local_id = nil expected_endpoint.claimed_id = claimed_id hacked_discover = Proc.new { |_claimed_id| ['unused', [expected_endpoint]] } idres = IdResHandler.new(resp_mesg, nil, nil, @endpoint) assert_log_matches('Performing discovery') { OpenID.with_method_overridden(:discover, hacked_discover) { idres.send(:verify_discovery_results) } } actual_endpoint = idres.instance_variable_get(:@endpoint) assert_equal(actual_endpoint, expected_endpoint) end end def test_openid2_no_op_endpoint assert_protocol_error("Missing required field: "\ "<#{OPENID2_NS}>op_endpoint") { call_verify({'ns'=>OPENID2_NS}) } end def test_openid2_local_id_no_claimed assert_verify_protocol_error('openid.identity is present without', {'ns' => OPENID2_NS, 'op_endpoint' => 'Phone Home', 'identity' => 'Jorge Lius Borges'}) end def test_openid2_no_local_id_claimed assert_log_matches() { assert_protocol_error('openid.claimed_id is present without') { call_verify({'ns' => OPENID2_NS, 'op_endpoint' => 'Phone Home', 'claimed_id' => 'Manuel Noriega'}) } } end def test_openid2_no_identifiers op_endpoint = 'Phone Home' result_endpoint = assert_log_matches() { call_verify({'ns' => OPENID2_NS, 'op_endpoint' => op_endpoint}) } assert(result_endpoint.is_op_identifier) assert_equal(op_endpoint, result_endpoint.server_url) assert(result_endpoint.claimed_id.nil?) end def test_openid2_no_endpoint_does_disco endpoint = OpenIDServiceEndpoint.new endpoint.claimed_id = 'monkeysoft' @endpoint = nil result = assert_log_matches('No pre-discovered') { call_verify_modify({'ns' => OPENID2_NS, 'identity' => 'sour grapes', 'claimed_id' => 'monkeysoft', 'op_endpoint' => 'Phone Home'}) do |idres| idres.instance_def(:discover_and_verify) do |claimed_id, endpoints| @endpoint = endpoint end end } assert_equal(endpoint, result) end def test_openid2_mismatched_does_disco @endpoint.claimed_id = 'nothing special, but different' @endpoint.local_id = 'green cheese' endpoint = OpenIDServiceEndpoint.new endpoint.claimed_id = 'monkeysoft' result = assert_log_matches('Error attempting to use stored', 'Attempting discovery') { call_verify_modify({'ns' => OPENID2_NS, 'identity' => 'sour grapes', 'claimed_id' => 'monkeysoft', 'op_endpoint' => 'Green Cheese'}) do |idres| idres.instance_def(:discover_and_verify) do |claimed_id, endpoints| @endpoint = endpoint end end } assert(endpoint.equal?(result)) end def test_verify_discovery_single_claimed_id_mismatch idres = IdResHandler.new(nil, nil) @endpoint.local_id = 'my identity' @endpoint.claimed_id = 'http://i-am-sam/' @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_2_0_TYPE] to_match = @endpoint.dup to_match.claimed_id = 'http://something.else/' e = assert_raises(ProtocolError) { idres.send(:verify_discovery_single, @endpoint, to_match) } assert(e.to_s =~ /different subjects/) end def test_openid1_1_verify_discovery_single_no_server_url idres = IdResHandler.new(nil, nil) @endpoint.local_id = 'my identity' @endpoint.claimed_id = 'http://i-am-sam/' @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_1_1_TYPE] to_match = @endpoint.dup to_match.claimed_id = 'http://i-am-sam/' to_match.type_uris = [OPENID_1_1_TYPE] to_match.server_url = nil idres.send(:verify_discovery_single, @endpoint, to_match) end def test_openid2_use_pre_discovered @endpoint.local_id = 'my identity' @endpoint.claimed_id = 'http://i-am-sam/' @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_2_0_TYPE] result = assert_log_matches() { call_verify({'ns' => OPENID2_NS, 'identity' => @endpoint.local_id, 'claimed_id' => @endpoint.claimed_id, 'op_endpoint' => @endpoint.server_url }) } assert(result.equal?(@endpoint)) end def test_openid2_use_pre_discovered_wrong_type text = "verify failed" me = self @endpoint.local_id = 'my identity' @endpoint.claimed_id = 'i am sam' @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_1_1_TYPE] endpoint = @endpoint msg = Message.from_openid_args({'ns' => OPENID2_NS, 'identity' => @endpoint.local_id, 'claimed_id' => @endpoint.claimed_id, 'op_endpoint' => @endpoint.server_url}) idres = IdResHandler.new(msg, nil, nil, @endpoint) idres.extend(InstanceDefExtension) idres.instance_def(:discover_and_verify) { |claimed_id, to_match| me.assert_equal(endpoint.claimed_id, to_match[0].claimed_id) me.assert_equal(claimed_id, endpoint.claimed_id) raise ProtocolError, text } assert_log_matches('Error attempting to use stored', 'Attempting discovery') { assert_protocol_error(text) { idres.send(:verify_discovery_results) } } end def test_openid1_use_pre_discovered @endpoint.local_id = 'my identity' @endpoint.claimed_id = 'http://i-am-sam/' @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_1_1_TYPE] result = assert_log_matches() { call_verify({'ns' => OPENID1_NS, 'identity' => @endpoint.local_id}) } assert(result.equal?(@endpoint)) end def test_openid1_use_pre_discovered_wrong_type verified_error = Class.new(Exception) @endpoint.local_id = 'my identity' @endpoint.claimed_id = 'i am sam' @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_2_0_TYPE] assert_log_matches('Error attempting to use stored', 'Attempting discovery') { assert_raises(verified_error) { call_verify_modify({'ns' => OPENID1_NS, 'identity' => @endpoint.local_id}) { |idres| idres.instance_def(:discover_and_verify) do |claimed_id, endpoints| raise verified_error end } } } end def test_openid2_fragment claimed_id = "http://unittest.invalid/" claimed_id_frag = claimed_id + "#fragment" @endpoint.local_id = 'my identity' @endpoint.claimed_id = claimed_id @endpoint.server_url = 'Phone Home' @endpoint.type_uris = [OPENID_2_0_TYPE] result = assert_log_matches() { call_verify({'ns' => OPENID2_NS, 'identity' => @endpoint.local_id, 'claimed_id' => claimed_id_frag, 'op_endpoint' => @endpoint.server_url}) } [:local_id, :server_url, :type_uris].each do |sym| assert_equal(@endpoint.send(sym), result.send(sym)) end assert_equal(claimed_id_frag, result.claimed_id) end def test_endpoint_without_local_id # An endpoint like this with no local_id is generated as a result of # e.g. Yadis discovery with no LocalID tag. @endpoint.server_url = "http://localhost:8000/openidserver" @endpoint.claimed_id = "http://localhost:8000/id/id-jo" to_match = OpenIDServiceEndpoint.new to_match.server_url = "http://localhost:8000/openidserver" to_match.claimed_id = "http://localhost:8000/id/id-jo" to_match.local_id = "http://localhost:8000/id/id-jo" idres = IdResHandler.new(nil, nil) assert_log_matches() { idres.send(:verify_discovery_single, @endpoint, to_match) } end end class IdResTopLevelTest < Minitest::Test def test_id_res endpoint = OpenIDServiceEndpoint.new endpoint.server_url = 'http://invalid/server' endpoint.claimed_id = 'http://my.url/' endpoint.local_id = 'http://invalid/username' endpoint.type_uris = [OPENID_2_0_TYPE] assoc = GoodAssoc.new store = Store::Memory.new store.store_association(endpoint.server_url, assoc) signed_fields = [ 'response_nonce', 'op_endpoint', 'assoc_handle', 'identity', 'claimed_id', 'ns', 'return_to', ] return_to = 'http://return.to/' args = { 'ns' => OPENID2_NS, 'return_to' => return_to, 'claimed_id' => endpoint.claimed_id, 'identity' => endpoint.local_id, 'assoc_handle' => assoc.handle, 'op_endpoint' => endpoint.server_url, 'response_nonce' => Nonce.mk_nonce, 'signed' => signed_fields.join(','), 'sig' => GOODSIG, } msg = Message.from_openid_args(args) idres = OpenID::Consumer::IdResHandler.new(msg, return_to, store, endpoint) assert_equal(idres.signed_fields, signed_fields.map {|f|'openid.' + f}) end end class DiscoverAndVerifyTest < Minitest::Test include ProtocolErrorMixin include TestUtil OpenID.extend(OverrideMethodMixin) def test_no_services me = self disco = Proc.new do |e| me.assert_equal(e, :sentinel) [:undefined, []] end endpoint = OpenIDServiceEndpoint.new endpoint.claimed_id = :sentinel idres = IdResHandler.new(nil, nil) assert_log_matches('Performing discovery on') do assert_protocol_error('No OpenID information found') do OpenID.with_method_overridden(:discover, disco) do idres.send(:discover_and_verify, :sentinel, [endpoint]) end end end end end class VerifyDiscoveredServicesTest < Minitest::Test include ProtocolErrorMixin include TestUtil def test_no_services endpoint = OpenIDServiceEndpoint.new endpoint.claimed_id = :sentinel idres = IdResHandler.new(nil, nil) assert_log_matches('Discovery verification failure') do assert_protocol_error('No matching endpoint') do idres.send(:verify_discovered_services, 'http://bogus.id/', [], [endpoint]) end end end end end end end ruby-openid-2.7.0debian.orig/test/test_xrires.rb0000644000175000017500000000502012512544714021170 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/yadis/xrires' module OpenID module Yadis class XRDSFetcher def initialize(results) @results = results end def fetch(url, body=nil, headers=nil, redirect_limit=nil) if !@results.empty? return @results.shift end nil end end class ProxyQueryTestCase < Minitest::Test def setup @proxy_url = 'http://xri.example.com/' @proxy = XRI::ProxyResolver.new(@proxy_url) @servicetype = 'xri://+i-service*(+forwarding)*($v*1.0)' @servicetype_enc = 'xri%3A%2F%2F%2Bi-service%2A%28%2Bforwarding%29%2A%28%24v%2A1.0%29' end def test_proxy_url st = @servicetype ste = @servicetype_enc args_esc = ["_xrd_r=application%2Fxrds%2Bxml", "_xrd_t=#{ste}"] pqu = @proxy.method('query_url') h = @proxy_url assert_match h + '=foo?', pqu.call('=foo', st) assert_match args_esc[0], pqu.call('=foo', st) assert_match args_esc[1], pqu.call('=foo', st) assert_match h + '=foo/bar?baz&', pqu.call('=foo/bar?baz', st) assert_match args_esc[0], pqu.call('=foo/bar?baz', st) assert_match args_esc[1], pqu.call('=foo/bar?baz', st) assert_match h + '=foo/bar?baz=quux&', pqu.call('=foo/bar?baz=quux', st) assert_match args_esc[0], pqu.call('=foo/bar?baz=quux', st) assert_match args_esc[1], pqu.call('=foo/bar?baz=quux', st) assert_match h + '=foo/bar?mi=fa&so=la&', pqu.call('=foo/bar?mi=fa&so=la', st) assert_match args_esc[0], pqu.call('=foo/bar?mi=fa&so=la', st) assert_match args_esc[1], pqu.call('=foo/bar?mi=fa&so=la', st) # With no service endpoint selection. args_esc = "_xrd_r=application%2Fxrds%2Bxml%3Bsep%3Dfalse" assert_match h + '=foo?', pqu.call('=foo', nil) assert_match args_esc, pqu.call('=foo', nil) end def test_proxy_url_qmarks st = @servicetype ste = @servicetype_enc args_esc = ["_xrd_r=application%2Fxrds%2Bxml", "_xrd_t=#{ste}"] pqu = @proxy.method('query_url') h = @proxy_url assert_match h + '=foo/bar??', pqu.call('=foo/bar?', st) assert_match args_esc[0], pqu.call('=foo/bar?', st) assert_match args_esc[1], pqu.call('=foo/bar?', st) assert_match h + '=foo/bar????', pqu.call('=foo/bar???', st) assert_match args_esc[0], pqu.call('=foo/bar???', st) assert_match args_esc[1], pqu.call('=foo/bar???', st) end end end end ruby-openid-2.7.0debian.orig/test/util.rb0000644000175000017500000000235012512544714017575 0ustar sbadiasbadia# Utilities that are only used in the testing code require 'stringio' module OpenID module TestUtil def assert_log_matches(*regexes) begin old_logger = Util.logger log_output = StringIO.new Util.logger = Logger.new(log_output) result = yield ensure Util.logger = old_logger end log_output.rewind log_lines = log_output.readlines assert_equal(regexes.length, log_lines.length, [regexes, log_lines].inspect) log_lines.zip(regexes) do |line, regex| assert_match(regex, line) end result end def assert_log_line_count(num_lines) begin old_logger = Util.logger log_output = StringIO.new Util.logger = Logger.new(log_output) result = yield ensure Util.logger = old_logger end log_output.rewind log_lines = log_output.readlines assert_equal(num_lines, log_lines.length) result end def silence_logging begin old_logger = Util.logger log_output = StringIO.new Util.logger = Logger.new(log_output) result = yield ensure Util.logger = old_logger end result end end end ruby-openid-2.7.0debian.orig/test/test_server.rb0000644000175000017500000025216612512544714021201 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'util' require 'uri' require 'openid/server' require 'openid/cryptutil' require 'openid/association' require 'openid/util' require 'openid/message' require 'openid/store/memory' require 'openid/dh' require 'openid/consumer/associationmanager' # In general, if you edit or add tests here, try to move in the # direction of testing smaller units. For testing the external # interfaces, we'll be developing an implementation-agnostic testing # suite. # for more, see /etc/ssh/moduli module OpenID ALT_MODULUS = 0xCAADDDEC1667FC68B5FA15D53C4E1532DD24561A1A2D47A12C01ABEA1E00731F6921AAC40742311FDF9E634BB7131BEE1AF240261554389A910425E044E88C8359B010F5AD2B80E29CB1A5B027B19D9E01A6F63A6F45E5D7ED2FF6A2A0085050A7D0CF307C3DB51D2490355907B4427C23A98DF1EB8ABEF2BA209BB7AFFE86A7 ALT_GEN = 5 class CatchLogs def catchlogs_setup @old_logger = Util.logger Util.logger = self.method('got_log_message') @messages = [] end def got_log_message(message) @messages << message end def teardown Util.logger = @old_logger end end class TestProtocolError < Minitest::Test def test_browserWithReturnTo return_to = "http://rp.unittest/consumer" # will be a ProtocolError raised by Decode or # CheckIDRequest.answer args = Message.from_post_args({ 'openid.mode' => 'monkeydance', 'openid.identity' => 'http://wagu.unittest/', 'openid.return_to' => return_to, }) e = Server::ProtocolError.new(args, "plucky") assert(e.has_return_to) expected_args = { 'openid.mode' => 'error', 'openid.error' => 'plucky', } _, result_args = e.encode_to_url.split('?', 2) result_args = Util.parse_query(result_args) assert_equal(result_args, expected_args) end def test_browserWithReturnTo_OpenID2_GET return_to = "http://rp.unittest/consumer" # will be a ProtocolError raised by Decode or # CheckIDRequest.answer args = Message.from_post_args({ 'openid.ns' => OPENID2_NS, 'openid.mode' => 'monkeydance', 'openid.identity' => 'http://wagu.unittest/', 'openid.claimed_id' => 'http://wagu.unittest/', 'openid.return_to' => return_to, }) e = Server::ProtocolError.new(args, "plucky") assert(e.has_return_to) expected_args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'error', 'openid.error' => 'plucky', } _, result_args = e.encode_to_url.split('?', 2) result_args = Util.parse_query(result_args) assert_equal(result_args, expected_args) end def test_browserWithReturnTo_OpenID2_POST return_to = "http://rp.unittest/consumer" + ('x' * OPENID1_URL_LIMIT) # will be a ProtocolError raised by Decode or # CheckIDRequest.answer args = Message.from_post_args({ 'openid.ns' => OPENID2_NS, 'openid.mode' => 'monkeydance', 'openid.identity' => 'http://wagu.unittest/', 'openid.claimed_id' => 'http://wagu.unittest/', 'openid.return_to' => return_to, }) e = Server::ProtocolError.new(args, "plucky") assert(e.has_return_to) assert(e.which_encoding == Server::ENCODE_HTML_FORM) assert(e.to_form_markup == e.to_message.to_form_markup( args.get_arg(OPENID_NS, 'return_to'))) end def test_browserWithReturnTo_OpenID1_exceeds_limit return_to = "http://rp.unittest/consumer" + ('x' * OPENID1_URL_LIMIT) # will be a ProtocolError raised by Decode or # CheckIDRequest.answer args = Message.from_post_args({ 'openid.mode' => 'monkeydance', 'openid.identity' => 'http://wagu.unittest/', 'openid.return_to' => return_to, }) e = Server::ProtocolError.new(args, "plucky") assert(e.has_return_to) expected_args = { 'openid.mode' => 'error', 'openid.error' => 'plucky', } assert(e.which_encoding == Server::ENCODE_URL) _, result_args = e.encode_to_url.split('?', 2) result_args = Util.parse_query(result_args) assert_equal(result_args, expected_args) end def test_noReturnTo # will be a ProtocolError raised by Decode or # CheckIDRequest.answer args = Message.from_post_args({ 'openid.mode' => 'zebradance', 'openid.identity' => 'http://wagu.unittest/', }) e = Server::ProtocolError.new(args, "waffles") assert(!e.has_return_to) expected = "error:waffles\nmode:error\n" assert_equal(e.encode_to_kvform, expected) end def test_no_message e = Server::ProtocolError.new(nil, "no message") assert(e.get_return_to.nil?) assert_equal(e.which_encoding, nil) end def test_which_encoding_no_message e = Server::ProtocolError.new(nil, "no message") assert(e.which_encoding.nil?) end end class TestDecode < Minitest::Test def setup @claimed_id = 'http://de.legating.de.coder.unittest/' @id_url = "http://decoder.am.unittest/" @rt_url = "http://rp.unittest/foobot/?qux=zam" @tr_url = "http://rp.unittest/" @assoc_handle = "{assoc}{handle}" @op_endpoint = 'http://endpoint.unittest/encode' @store = Store::Memory.new() @server = Server::Server.new(@store, @op_endpoint) @decode = Server::Decoder.new(@server).method('decode') end def test_none args = {} r = @decode.call(args) assert_equal(r, nil) end def test_irrelevant args = { 'pony' => 'spotted', 'sreg.mutant_power' => 'decaffinator', } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_bad args = { 'openid.mode' => 'twos-compliment', 'openid.pants' => 'zippered', } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_dictOfLists args = { 'openid.mode' => ['checkid_setup'], 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.trust_root' => @tr_url, } begin result = @decode.call(args) rescue ArgumentError => err assert !err.to_s.index('values').nil? else flunk("Expected ArgumentError, but got result #{result}") end end def test_checkidImmediate args = { 'openid.mode' => 'checkid_immediate', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.trust_root' => @tr_url, # should be ignored 'openid.some.extension' => 'junk', } r = @decode.call(args) assert(r.is_a?(Server::CheckIDRequest)) assert_equal(r.mode, "checkid_immediate") assert_equal(r.immediate, true) assert_equal(r.identity, @id_url) assert_equal(r.trust_root, @tr_url) assert_equal(r.return_to, @rt_url) assert_equal(r.assoc_handle, @assoc_handle) end def test_checkidImmediate_constructor r = Server::CheckIDRequest.new(@id_url, @rt_url, nil, @rt_url, true, @assoc_handle) assert(r.mode == 'checkid_immediate') assert(r.immediate) end def test_checkid_missing_return_to_and_trust_root args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.claimed_id' => @id_url, 'openid.assoc_handle' => @assoc_handle, } assert_raises(Server::ProtocolError) { m = Message.from_post_args(args) Server::CheckIDRequest.from_message(m, @op_endpoint) } end def test_checkid_id_select args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => IDENTIFIER_SELECT, 'openid.claimed_id' => IDENTIFIER_SELECT, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.realm' => @tr_url, } m = Message.from_post_args(args) req = Server::CheckIDRequest.from_message(m, @op_endpoint) assert(req.id_select) end def test_checkid_not_id_select args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.realm' => @tr_url, } id_args = [ {'openid.claimed_id' => IDENTIFIER_SELECT, 'openid.identity' => 'http://bogus.com/'}, {'openid.claimed_id' => 'http://bogus.com/', 'openid.identity' => 'http://bogus.com/'}, ] id_args.each { |id| m = Message.from_post_args(args.merge(id)) req = Server::CheckIDRequest.from_message(m, @op_endpoint) assert(!req.id_select) } end def test_checkidSetup args = { 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.trust_root' => @tr_url, } r = @decode.call(args) assert(r.is_a?(Server::CheckIDRequest)) assert_equal(r.mode, "checkid_setup") assert_equal(r.immediate, false) assert_equal(r.identity, @id_url) assert_equal(r.trust_root, @tr_url) assert_equal(r.return_to, @rt_url) end def test_checkidSetupOpenID2 args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.claimed_id' => @claimed_id, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.realm' => @tr_url, } r = @decode.call(args) assert(r.is_a?(Server::CheckIDRequest)) assert_equal(r.mode, "checkid_setup") assert_equal(r.immediate, false) assert_equal(r.identity, @id_url) assert_equal(r.claimed_id, @claimed_id) assert_equal(r.trust_root, @tr_url) assert_equal(r.return_to, @rt_url) end def test_checkidSetupNoClaimedIDOpenID2 args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.realm' => @tr_url, } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_checkidSetupNoIdentityOpenID2 args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.realm' => @tr_url, } r = @decode.call(args) assert(r.is_a?(Server::CheckIDRequest)) assert_equal(r.mode, "checkid_setup") assert_equal(r.immediate, false) assert_equal(r.identity, nil) assert_equal(r.trust_root, @tr_url) assert_equal(r.return_to, @rt_url) end def test_checkidSetupNoReturnOpenID1 # Make sure an OpenID 1 request cannot be decoded if it lacks a # return_to. args = { 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.trust_root' => @tr_url, } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_checkidSetupNoReturnOpenID2 # Make sure an OpenID 2 request with no return_to can be decoded, # and make sure a response to such a request raises # NoReturnToError. args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.claimed_id' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.realm' => @tr_url, } req = @decode.call(args) assert(req.is_a?(Server::CheckIDRequest)) assert_raises(Server::NoReturnToError) { req.answer(false) } assert_raises(Server::NoReturnToError) { req.encode_to_url('bogus') } assert_raises(Server::NoReturnToError) { req.cancel_url } end def test_checkidSetupRealmRequiredOpenID2 # Make sure that an OpenID 2 request which lacks return_to cannot # be decoded if it lacks a realm. Spec => This value # (openid.realm) MUST be sent if openid.return_to is omitted. args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_checkidSetupBadReturn args = { 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => 'not a url', } begin result = @decode.call(args) rescue Server::ProtocolError => err assert(err.openid_message) else flunk("Expected ProtocolError, instead returned with #{result}") end end def test_checkidSetupUntrustedReturn args = { 'openid.mode' => 'checkid_setup', 'openid.identity' => @id_url, 'openid.assoc_handle' => @assoc_handle, 'openid.return_to' => @rt_url, 'openid.trust_root' => 'http://not-the-return-place.unittest/', } begin result = @decode.call(args) rescue Server::UntrustedReturnURL => err assert(err.openid_message, err.to_s) else flunk("Expected UntrustedReturnURL, instead returned with #{result}") end end def test_checkidSetupUntrustedReturn_Constructor assert_raises(Server::UntrustedReturnURL) { Server::CheckIDRequest.new(@id_url, @rt_url, nil, 'http://not-the-return-place.unittest/', false, @assoc_handle) } end def test_checkidSetupMalformedReturnURL_Constructor assert_raises(Server::MalformedReturnURL) { Server::CheckIDRequest.new(@id_url, 'bogus://return.url', nil, 'http://trustroot.com/', false, @assoc_handle) } end def test_checkAuth args = { 'openid.mode' => 'check_authentication', 'openid.assoc_handle' => '{dumb}{handle}', 'openid.sig' => 'sigblob', 'openid.signed' => 'identity,return_to,response_nonce,mode', 'openid.identity' => 'signedval1', 'openid.return_to' => 'signedval2', 'openid.response_nonce' => 'signedval3', 'openid.baz' => 'unsigned', } r = @decode.call(args) assert(r.is_a?(Server::CheckAuthRequest)) assert_equal(r.mode, 'check_authentication') assert_equal(r.sig, 'sigblob') end def test_checkAuthMissingSignature args = { 'openid.mode' => 'check_authentication', 'openid.assoc_handle' => '{dumb}{handle}', 'openid.signed' => 'foo,bar,mode', 'openid.foo' => 'signedval1', 'openid.bar' => 'signedval2', 'openid.baz' => 'unsigned', } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_checkAuthAndInvalidate args = { 'openid.mode' => 'check_authentication', 'openid.assoc_handle' => '{dumb}{handle}', 'openid.invalidate_handle' => '[[SMART_handle]]', 'openid.sig' => 'sigblob', 'openid.signed' => 'identity,return_to,response_nonce,mode', 'openid.identity' => 'signedval1', 'openid.return_to' => 'signedval2', 'openid.response_nonce' => 'signedval3', 'openid.baz' => 'unsigned', } r = @decode.call(args) assert(r.is_a?(Server::CheckAuthRequest)) assert_equal(r.invalidate_handle, '[[SMART_handle]]') end def test_associateDH args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "Rzup9265tw==", } r = @decode.call(args) assert(r.is_a?(Server::AssociateRequest)) assert_equal(r.mode, "associate") assert_equal(r.session.session_type, "DH-SHA1") assert_equal(r.assoc_type, "HMAC-SHA1") assert(r.session.consumer_pubkey) end def test_associateDHMissingKey # Trying DH assoc w/o public key args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', } # Using DH-SHA1 without supplying dh_consumer_public is an error. assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_associateDHpubKeyNotB64 args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "donkeydonkeydonkey", } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_associateDHModGen # test dh with non-default but valid values for dh_modulus and # dh_gen args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "Rzup9265tw==", 'openid.dh_modulus' => CryptUtil.num_to_base64(ALT_MODULUS), 'openid.dh_gen' => CryptUtil.num_to_base64(ALT_GEN) , } r = @decode.call(args) assert(r.is_a?(Server::AssociateRequest)) assert_equal(r.mode, "associate") assert_equal(r.session.session_type, "DH-SHA1") assert_equal(r.assoc_type, "HMAC-SHA1") assert_equal(r.session.dh.modulus, ALT_MODULUS) assert_equal(r.session.dh.generator, ALT_GEN) assert(r.session.consumer_pubkey) end def test_associateDHCorruptModGen # test dh with non-default but valid values for dh_modulus and # dh_gen args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "Rzup9265tw==", 'openid.dh_modulus' => 'pizza', 'openid.dh_gen' => 'gnocchi', } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_associateDHMissingGen args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "Rzup9265tw==", 'openid.dh_modulus' => 'pizza', } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_associateDHMissingMod args = { 'openid.mode' => 'associate', 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "Rzup9265tw==", 'openid.dh_gen' => 'pizza', } assert_raises(Server::ProtocolError) { @decode.call(args) } end # def test_associateDHInvalidModGen(self): # # test dh with properly encoded values that are not a valid # # modulus/generator combination. # args = { # 'openid.mode': 'associate', # 'openid.session_type': 'DH-SHA1', # 'openid.dh_consumer_public': "Rzup9265tw==", # 'openid.dh_modulus': cryptutil.longToBase64(9), # 'openid.dh_gen': cryptutil.longToBase64(27) , # } # self.failUnlessRaises(server.ProtocolError, self.decode, args) # test_associateDHInvalidModGen.todo = "low-priority feature" def test_associateWeirdSession args = { 'openid.mode' => 'associate', 'openid.session_type' => 'FLCL6', 'openid.dh_consumer_public' => "YQ==\n", } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_associatePlain args = { 'openid.mode' => 'associate', } r = @decode.call(args) assert(r.is_a?(Server::AssociateRequest)) assert_equal(r.mode, "associate") assert_equal(r.session.session_type, "no-encryption") assert_equal(r.assoc_type, "HMAC-SHA1") end def test_nomode args = { 'openid.session_type' => 'DH-SHA1', 'openid.dh_consumer_public' => "my public keeey", } assert_raises(Server::ProtocolError) { @decode.call(args) } end def test_invalidns args = {'openid.ns' => 'Vegetables', 'openid.mode' => 'associate'} begin @decode.call(args) rescue Server::ProtocolError => err assert(err.openid_message) assert(err.to_s.index('Vegetables')) end end end class BogusEncoder < Server::Encoder def encode(response) return "BOGUS" end end class BogusDecoder < Server::Decoder def decode(query) return "BOGUS" end end class TestEncode < Minitest::Test def setup @encoder = Server::Encoder.new @encode = @encoder.method('encode') @op_endpoint = 'http://endpoint.unittest/encode' @store = Store::Memory.new @server = Server::Server.new(@store, @op_endpoint) end def test_id_res_OpenID2_GET # Check that when an OpenID 2 response does not exceed the OpenID # 1 message size, a GET response (i.e., redirect) is issued. request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'ns' => OPENID2_NS, 'mode' => 'id_res', 'identity' => request.identity, 'claimed_id' => request.identity, 'return_to' => request.return_to, }) assert(!response.render_as_form) assert(response.which_encoding == Server::ENCODE_URL) webresponse = @encode.call(response) assert(webresponse.headers.member?('location')) end def test_id_res_OpenID2_POST # Check that when an OpenID 2 response exceeds the OpenID 1 # message size, a POST response (i.e., an HTML form) is returned. request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'ns' => OPENID2_NS, 'mode' => 'id_res', 'identity' => request.identity, 'claimed_id' => request.identity, 'return_to' => 'x' * OPENID1_URL_LIMIT, }) assert(response.render_as_form) assert(response.encode_to_url.length > OPENID1_URL_LIMIT) assert(response.which_encoding == Server::ENCODE_HTML_FORM) webresponse = @encode.call(response) assert_equal(webresponse.body, response.to_form_markup) end def test_to_form_markup request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'ns' => OPENID2_NS, 'mode' => 'id_res', 'identity' => request.identity, 'claimed_id' => request.identity, 'return_to' => 'x' * OPENID1_URL_LIMIT, }) form_markup = response.to_form_markup({'foo'=>'bar'}) assert(/ foo="bar"/ =~ form_markup, form_markup) end def test_to_html request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'ns' => OPENID2_NS, 'mode' => 'id_res', 'identity' => request.identity, 'claimed_id' => request.identity, 'return_to' => 'x' * OPENID1_URL_LIMIT, }) html = response.to_html assert(html) end def test_id_res_OpenID1_exceeds_limit # Check that when an OpenID 1 response exceeds the OpenID 1 # message size, a GET response is issued. Technically, this # shouldn't be permitted by the library, but this test is in place # to preserve the status quo for OpenID 1. request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID1_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'mode' => 'id_res', 'identity' => request.identity, 'return_to' => 'x' * OPENID1_URL_LIMIT, }) assert(!response.render_as_form) assert(response.encode_to_url.length > OPENID1_URL_LIMIT) assert(response.which_encoding == Server::ENCODE_URL) webresponse = @encode.call(response) assert_equal(webresponse.headers['location'], response.encode_to_url) end def test_id_res request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID1_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'mode' => 'id_res', 'identity' => request.identity, 'return_to' => request.return_to, }) webresponse = @encode.call(response) assert_equal(webresponse.code, Server::HTTP_REDIRECT) assert(webresponse.headers.member?('location')) location = webresponse.headers['location'] assert(location.start_with?(request.return_to), sprintf("%s does not start with %s", location, request.return_to)) # argh. q2 = Util.parse_query(URI::parse(location).query) expected = response.fields.to_post_args assert_equal(q2, expected) end def test_cancel request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'mode' => 'cancel', }) webresponse = @encode.call(response) assert_equal(webresponse.code, Server::HTTP_REDIRECT) assert(webresponse.headers.member?('location')) end def test_cancel_to_form request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'mode' => 'cancel', }) form = response.to_form_markup assert(form.index(request.return_to)) end def test_assocReply msg = Message.new(OPENID2_NS) msg.set_arg(OPENID2_NS, 'session_type', 'no-encryption') request = Server::AssociateRequest.from_message(msg) response = Server::OpenIDResponse.new(request) response.fields = Message.from_post_args( {'openid.assoc_handle' => "every-zig"}) webresponse = @encode.call(response) body = "assoc_handle:every-zig\n" assert_equal(webresponse.code, Server::HTTP_OK) assert_equal(webresponse.headers, {}) assert_equal(webresponse.body, body) end def test_checkauthReply request = Server::CheckAuthRequest.new('a_sock_monkey', 'siggggg', []) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'is_valid' => 'true', 'invalidate_handle' => 'xXxX:xXXx' }) body = "invalidate_handle:xXxX:xXXx\nis_valid:true\n" webresponse = @encode.call(response) assert_equal(webresponse.code, Server::HTTP_OK) assert_equal(webresponse.headers, {}) assert_equal(webresponse.body, body) end def test_unencodableError args = Message.from_post_args({ 'openid.identity' => 'http://limu.unittest/', }) e = Server::ProtocolError.new(args, "wet paint") assert_raises(Server::EncodingError) { @encode.call(e) } end def test_encodableError args = Message.from_post_args({ 'openid.mode' => 'associate', 'openid.identity' => 'http://limu.unittest/', }) body="error:snoot\nmode:error\n" webresponse = @encode.call(Server::ProtocolError.new(args, "snoot")) assert_equal(webresponse.code, Server::HTTP_ERROR) assert_equal(webresponse.headers, {}) assert_equal(webresponse.body, body) end end class TestSigningEncode < Minitest::Test def setup @_dumb_key = Server::Signatory._dumb_key @_normal_key = Server::Signatory._normal_key @store = Store::Memory.new() @server = Server::Server.new(@store, "http://signing.unittest/enc") @request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) @request.message = Message.new(OPENID2_NS) @response = Server::OpenIDResponse.new(@request) @response.fields = Message.from_openid_args({ 'mode' => 'id_res', 'identity' => @request.identity, 'return_to' => @request.return_to, }) @signatory = Server::Signatory.new(@store) @encoder = Server::SigningEncoder.new(@signatory) @encode = @encoder.method('encode') end def test_idres assoc_handle = '{bicycle}{shed}' @store.store_association( @_normal_key, Association.from_expires_in(60, assoc_handle, 'sekrit', 'HMAC-SHA1')) @request.assoc_handle = assoc_handle webresponse = @encode.call(@response) assert_equal(webresponse.code, Server::HTTP_REDIRECT) assert(webresponse.headers.member?('location')) location = webresponse.headers['location'] query = Util.parse_query(URI::parse(location).query) assert(query.member?('openid.sig')) assert(query.member?('openid.assoc_handle')) assert(query.member?('openid.signed')) end def test_idresDumb webresponse = @encode.call(@response) assert_equal(webresponse.code, Server::HTTP_REDIRECT) assert(webresponse.headers.has_key?('location')) location = webresponse.headers['location'] query = Util.parse_query(URI::parse(location).query) assert(query.member?('openid.sig')) assert(query.member?('openid.assoc_handle')) assert(query.member?('openid.signed')) end def test_forgotStore @encoder.signatory = nil assert_raises(ArgumentError) { @encode.call(@response) } end def test_cancel request = Server::CheckIDRequest.new( 'http://bombom.unittest/', 'http://burr.unittest/999', @server.op_endpoint, 'http://burr.unittest/', false, nil) request.message = Message.new(OPENID2_NS) response = Server::OpenIDResponse.new(request) response.fields.set_arg(OPENID_NS, 'mode', 'cancel') webresponse = @encode.call(response) assert_equal(webresponse.code, Server::HTTP_REDIRECT) assert(webresponse.headers.has_key?('location')) location = webresponse.headers['location'] query = Util.parse_query(URI::parse(location).query) assert !query.has_key?('openid.sig') end def test_assocReply msg = Message.new(OPENID2_NS) msg.set_arg(OPENID2_NS, 'session_type', 'no-encryption') request = Server::AssociateRequest.from_message(msg) response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({'assoc_handle' => "every-zig"}) webresponse = @encode.call(response) body = "assoc_handle:every-zig\n" assert_equal(webresponse.code, Server::HTTP_OK) assert_equal(webresponse.headers, {}) assert_equal(webresponse.body, body) end def test_alreadySigned @response.fields.set_arg(OPENID_NS, 'sig', 'priorSig==') assert_raises(Server::AlreadySigned) { @encode.call(@response) } end end class TestCheckID < Minitest::Test def setup @op_endpoint = 'http://endpoint.unittest/' @store = Store::Memory.new() @server = Server::Server.new(@store, @op_endpoint) @request = Server::CheckIDRequest.new( 'http://bambam.unittest/', 'http://bar.unittest/999', @server.op_endpoint, 'http://bar.unittest/', false) @request.message = Message.new(OPENID2_NS) end def test_trustRootInvalid @request.trust_root = "http://foo.unittest/17" @request.return_to = "http://foo.unittest/39" assert(!@request.trust_root_valid()) end def test_trustRootInvalid_modified @request.trust_root = "does://not.parse/" @request.message = :sentinel begin result = @request.trust_root_valid rescue Server::MalformedTrustRoot => why assert_equal(:sentinel, why.openid_message) else flunk("Expected MalformedTrustRoot, got #{result.inspect}") end end def test_trustRootvalid_absent_trust_root @request.trust_root = nil assert(@request.trust_root_valid()) end def test_trustRootValid @request.trust_root = "http://foo.unittest/" @request.return_to = "http://foo.unittest/39" assert(@request.trust_root_valid()) end def test_trustRootValidNoReturnTo request = Server::CheckIDRequest.new( 'http://bambam.unittest/', nil, @server.op_endpoint, 'http://bar.unittest/', false) assert(request.trust_root_valid()) end def test_returnToVerified_callsVerify # Make sure that verifyReturnTo is calling the trustroot # function verifyReturnTo # Ensure that exceptions are passed through sentinel = Exception.new() __req = @request tc = self vrfyExc = Proc.new { |trust_root, return_to| tc.assert_equal(__req.trust_root, trust_root) tc.assert_equal(__req.return_to, return_to) raise sentinel } TrustRoot.extend(OverrideMethodMixin) TrustRoot.with_method_overridden(:verify_return_to, vrfyExc) do begin @request.return_to_verified() flunk("Expected sentinel to be raised, got success") rescue Exception => e assert(e.equal?(sentinel), [e, sentinel].inspect) end end # Ensure that True and False are passed through unchanged constVerify = Proc.new { |val| verify = Proc.new { |trust_root, return_to| tc.assert_equal(__req.trust_root, trust_root) tc.assert_equal(__req.request.return_to, return_to) return val } return verify } [true, false].each { |val| verifier = constVerify.call(val) TrustRoot.with_method_overridden(:verify_return_to, verifier) do assert_equal(val, @request.return_to_verified()) end } end def _expectAnswer(answer, identity=nil, claimed_id=nil) expected_list = [ ['mode', 'id_res'], ['return_to', @request.return_to], ['op_endpoint', @op_endpoint], ] if identity expected_list << ['identity', identity] if claimed_id expected_list << ['claimed_id', claimed_id] else expected_list << ['claimed_id', identity] end end expected_list.each { |k, expected| actual = answer.fields.get_arg(OPENID_NS, k) assert_equal(expected, actual, sprintf("%s: expected %s, got %s", k, expected, actual)) } assert(answer.fields.has_key?(OPENID_NS, 'response_nonce')) assert(answer.fields.get_openid_namespace() == OPENID2_NS) # One for nonce, one for ns assert_equal(answer.fields.to_post_args.length, expected_list.length + 2, answer.fields.to_post_args.inspect) end def test_answerAllow # Check the fields specified by "Positive Assertions" # # including mode=id_res, identity, claimed_id, op_endpoint, # return_to answer = @request.answer(true) assert_equal(answer.request, @request) _expectAnswer(answer, @request.identity) end def test_answerAllowDelegatedIdentity @request.claimed_id = 'http://delegating.unittest/' answer = @request.answer(true) _expectAnswer(answer, @request.identity, @request.claimed_id) end def test_answerAllowWithoutIdentityReally @request.identity = nil answer = @request.answer(true) assert_equal(answer.request, @request) _expectAnswer(answer) end def test_answerAllowAnonymousFail @request.identity = nil # XXX - Check on this, I think this behavior is legal in OpenID # 2.0? assert_raises(ArgumentError) { @request.answer(true, nil, "=V") } end def test_answerAllowWithIdentity @request.identity = IDENTIFIER_SELECT selected_id = 'http://anon.unittest/9861' answer = @request.answer(true, nil, selected_id) _expectAnswer(answer, selected_id) end def test_answerAllowWithNoIdentity @request.identity = IDENTIFIER_SELECT assert_raises(ArgumentError) { @request.answer(true, nil, nil) } end def test_immediate_openid1_no_identity @request.message = Message.new(OPENID1_NS) @request.immediate = true @request.mode = 'checkid_immediate' resp = @request.answer(false) assert(resp.fields.get_arg(OPENID_NS, 'mode') == 'id_res') end def test_checkid_setup_openid1_no_identity @request.message = Message.new(OPENID1_NS) @request.immediate = false @request.mode = 'checkid_setup' resp = @request.answer(false) assert(resp.fields.get_arg(OPENID_NS, 'mode') == 'cancel') end def test_immediate_openid1_no_server_url @request.message = Message.new(OPENID1_NS) @request.immediate = true @request.mode = 'checkid_immediate' @request.op_endpoint = nil assert_raises(ArgumentError) { @request.answer(false) } end def test_immediate_encode_to_url @request.message = Message.new(OPENID1_NS) @request.immediate = true @request.mode = 'checkid_immediate' @request.trust_root = "BOGUS" @request.assoc_handle = "ASSOC" server_url = "http://server.com/server" url = @request.encode_to_url(server_url) assert(url.start_with?(server_url)) _, query = url.split("?", 2) args = Util.parse_query(query) m = Message.from_post_args(args) assert(m.get_arg(OPENID_NS, 'trust_root') == "BOGUS") assert(m.get_arg(OPENID_NS, 'assoc_handle') == "ASSOC") assert(m.get_arg(OPENID_NS, 'mode'), "checkid_immediate") assert(m.get_arg(OPENID_NS, 'identity') == @request.identity) assert(m.get_arg(OPENID_NS, 'claimed_id') == @request.claimed_id) assert(m.get_arg(OPENID_NS, 'return_to') == @request.return_to) end def test_answerAllowWithDelegatedIdentityOpenID2 # Answer an IDENTIFIER_SELECT case with a delegated identifier. # claimed_id delegates to selected_id here. @request.identity = IDENTIFIER_SELECT selected_id = 'http://anon.unittest/9861' claimed_id = 'http://monkeyhat.unittest/' answer = @request.answer(true, nil, selected_id, claimed_id) _expectAnswer(answer, selected_id, claimed_id) end def test_answerAllowWithDelegatedIdentityOpenID1 # claimed_id parameter doesn't exist in OpenID 1. @request.message = Message.new(OPENID1_NS) # claimed_id delegates to selected_id here. @request.identity = IDENTIFIER_SELECT selected_id = 'http://anon.unittest/9861' claimed_id = 'http://monkeyhat.unittest/' assert_raises(Server::VersionError) { @request.answer(true, nil, selected_id, claimed_id) } end def test_answerAllowWithAnotherIdentity # XXX - Check on this, I think this behavior is legal in OpenID # 2.0? assert_raises(ArgumentError){ @request.answer(true, nil, "http://pebbles.unittest/") } end def test_answerAllowNoIdentityOpenID1 @request.message = Message.new(OPENID1_NS) @request.identity = nil assert_raises(ArgumentError) { @request.answer(true, nil, nil) } end def test_answerAllowForgotEndpoint @request.op_endpoint = nil assert_raises(RuntimeError) { @request.answer(true) } end def test_checkIDWithNoIdentityOpenID1 msg = Message.new(OPENID1_NS) msg.set_arg(OPENID_NS, 'return_to', 'bogus') msg.set_arg(OPENID_NS, 'trust_root', 'bogus') msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'assoc_handle', 'bogus') assert_raises(Server::ProtocolError) { Server::CheckIDRequest.from_message(msg, @server) } end def test_fromMessageClaimedIDWithoutIdentityOpenID2 msg = Message.new(OPENID2_NS) msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'return_to', 'http://invalid:8000/rt') msg.set_arg(OPENID_NS, 'claimed_id', 'https://example.myopenid.com') assert_raises(Server::ProtocolError) { Server::CheckIDRequest.from_message(msg, @server) } end def test_fromMessageIdentityWithoutClaimedIDOpenID2 msg = Message.new(OPENID2_NS) msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'return_to', 'http://invalid:8000/rt') msg.set_arg(OPENID_NS, 'identity', 'https://example.myopenid.com') assert_raises(Server::ProtocolError) { Server::CheckIDRequest.from_message(msg, @server) } end def test_fromMessageWithEmptyTrustRoot return_to = 'http://some.url/foo?bar=baz' msg = Message.from_post_args({ 'openid.assoc_handle' => '{blah}{blah}{OZivdQ==}', 'openid.claimed_id' => 'http://delegated.invalid/', 'openid.identity' => 'http://op-local.example.com/', 'openid.mode' => 'checkid_setup', 'openid.ns' => 'http://openid.net/signon/1.0', 'openid.return_to' => return_to, 'openid.trust_root' => '' }); result = Server::CheckIDRequest.from_message(msg, @server) assert_equal(return_to, result.trust_root) end def test_trustRootOpenID1 # Ignore openid.realm in OpenID 1 msg = Message.new(OPENID1_NS) msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'trust_root', 'http://trustroot.com/') msg.set_arg(OPENID_NS, 'realm', 'http://fake_trust_root/') msg.set_arg(OPENID_NS, 'return_to', 'http://trustroot.com/foo') msg.set_arg(OPENID_NS, 'assoc_handle', 'bogus') msg.set_arg(OPENID_NS, 'identity', 'george') result = Server::CheckIDRequest.from_message(msg, @server.op_endpoint) assert(result.trust_root == 'http://trustroot.com/') end def test_trustRootOpenID2 # Ignore openid.trust_root in OpenID 2 msg = Message.new(OPENID2_NS) msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'realm', 'http://trustroot.com/') msg.set_arg(OPENID_NS, 'trust_root', 'http://fake_trust_root/') msg.set_arg(OPENID_NS, 'return_to', 'http://trustroot.com/foo') msg.set_arg(OPENID_NS, 'assoc_handle', 'bogus') msg.set_arg(OPENID_NS, 'identity', 'george') msg.set_arg(OPENID_NS, 'claimed_id', 'george') result = Server::CheckIDRequest.from_message(msg, @server.op_endpoint) assert(result.trust_root == 'http://trustroot.com/') end def test_answerAllowNoTrustRoot @request.trust_root = nil answer = @request.answer(true) assert_equal(answer.request, @request) _expectAnswer(answer, @request.identity) end def test_answerImmediateDenyOpenID2 # Look for mode=setup_needed in checkid_immediate negative # response in OpenID 2 case. # # See specification Responding to Authentication Requests / # Negative Assertions / In Response to Immediate Requests. @request.mode = 'checkid_immediate' @request.immediate = true server_url = "http://setup-url.unittest/" # crappiting setup_url, you dirty my interface with your presence! answer = @request.answer(false, server_url) assert_equal(answer.request, @request) assert_equal(answer.fields.to_post_args.length, 3, answer.fields) assert_equal(answer.fields.get_openid_namespace, OPENID2_NS) assert_equal(answer.fields.get_arg(OPENID_NS, 'mode'), 'setup_needed') # user_setup_url no longer required. end def test_answerImmediateDenyOpenID1 # Look for user_setup_url in checkid_immediate negative response # in OpenID 1 case. @request.message = Message.new(OPENID1_NS) @request.mode = 'checkid_immediate' @request.immediate = true @request.claimed_id = 'http://claimed-id.test/' server_url = "http://setup-url.unittest/" # crappiting setup_url, you dirty my interface with your presence! answer = @request.answer(false, server_url) assert_equal(answer.request, @request) assert_equal(2, answer.fields.to_post_args.length, answer.fields) assert_equal(OPENID1_NS, answer.fields.get_openid_namespace) assert_equal('id_res', answer.fields.get_arg(OPENID_NS, 'mode')) usu = answer.fields.get_arg(OPENID_NS, 'user_setup_url', '') assert(usu.start_with?(server_url)) expected_substr = 'openid.claimed_id=http%3A%2F%2Fclaimed-id.test%2F' assert(!usu.index(expected_substr).nil?, usu) end def test_answerSetupDeny answer = @request.answer(false) assert_equal(answer.fields.get_args(OPENID_NS), { 'mode' => 'cancel', }) end def test_encodeToURL server_url = 'http://openid-server.unittest/' result = @request.encode_to_url(server_url) # How to check? How about a round-trip test. _, result_args = result.split('?', 2) result_args = Util.parse_query(result_args) message = Message.from_post_args(result_args) rebuilt_request = Server::CheckIDRequest.from_message(message, @server.op_endpoint) @request.message = message @request.instance_variables.each { |var| assert_equal(@request.instance_variable_get(var), rebuilt_request.instance_variable_get(var), var) } end def test_getCancelURL url = @request.cancel_url rt, query_string = url.split('?', -1) assert_equal(@request.return_to, rt) query = Util.parse_query(query_string) assert_equal(query, {'openid.mode' => 'cancel', 'openid.ns' => OPENID2_NS}) end def test_getCancelURLimmed @request.mode = 'checkid_immediate' @request.immediate = true assert_raises(ArgumentError) { @request.cancel_url } end def test_fromMessageWithoutTrustRoot msg = Message.new(OPENID2_NS) msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'return_to', 'http://real.trust.root/foo') msg.set_arg(OPENID_NS, 'assoc_handle', 'bogus') msg.set_arg(OPENID_NS, 'identity', 'george') msg.set_arg(OPENID_NS, 'claimed_id', 'george') result = Server::CheckIDRequest.from_message(msg, @server.op_endpoint) assert_equal(result.trust_root, 'http://real.trust.root/foo') end def test_fromMessageWithoutTrustRootOrReturnTo msg = Message.new(OPENID2_NS) msg.set_arg(OPENID_NS, 'mode', 'checkid_setup') msg.set_arg(OPENID_NS, 'assoc_handle', 'bogus') msg.set_arg(OPENID_NS, 'identity', 'george') msg.set_arg(OPENID_NS, 'claimed_id', 'george') assert_raises(Server::ProtocolError) { Server::CheckIDRequest.from_message(msg, @server.op_endpoint) } end end class TestCheckIDExtension < Minitest::Test def setup @op_endpoint = 'http://endpoint.unittest/ext' @store = Store::Memory.new() @server = Server::Server.new(@store, @op_endpoint) @request = Server::CheckIDRequest.new( 'http://bambam.unittest/', 'http://bar.unittest/999', @server.op_endpoint, 'http://bar.unittest/', false) @request.message = Message.new(OPENID2_NS) @response = Server::OpenIDResponse.new(@request) @response.fields.set_arg(OPENID_NS, 'mode', 'id_res') @response.fields.set_arg(OPENID_NS, 'blue', 'star') end def test_addField namespace = 'something:' @response.fields.set_arg(namespace, 'bright', 'potato') assert_equal(@response.fields.get_args(OPENID_NS), {'blue' => 'star', 'mode' => 'id_res', }) assert_equal(@response.fields.get_args(namespace), {'bright' => 'potato'}) end def test_addFields namespace = 'mi5:' args = {'tangy' => 'suspenders', 'bravo' => 'inclusion'} @response.fields.update_args(namespace, args) assert_equal(@response.fields.get_args(OPENID_NS), {'blue' => 'star', 'mode' => 'id_res', }) assert_equal(@response.fields.get_args(namespace), args) end end class MockSignatory attr_accessor :isValid, :assocs def initialize(assoc) @isValid = true @assocs = [assoc] end def verify(assoc_handle, message) Util.assert(message.has_key?(OPENID_NS, "sig")) if self.assocs.member?([true, assoc_handle]) return @isValid else return false end end def get_association(assoc_handle, dumb) if self.assocs.member?([dumb, assoc_handle]) # This isn't a valid implementation for many uses of this # function, mind you. return true else return nil end end def invalidate(assoc_handle, dumb) if self.assocs.member?([dumb, assoc_handle]) @assocs.delete([dumb, assoc_handle]) end end end class TestCheckAuth < Minitest::Test def setup @assoc_handle = 'mooooooooo' @message = Message.from_post_args({ 'openid.sig' => 'signarture', 'one' => 'alpha', 'two' => 'beta', }) @request = Server::CheckAuthRequest.new( @assoc_handle, @message) @request.message = Message.new(OPENID2_NS) @signatory = MockSignatory.new([true, @assoc_handle]) end def test_to_s @request.to_s end def test_valid r = @request.answer(@signatory) assert_equal({'is_valid' => 'true'}, r.fields.get_args(OPENID_NS)) assert_equal(r.request, @request) end def test_invalid @signatory.isValid = false r = @request.answer(@signatory) assert_equal({'is_valid' => 'false'}, r.fields.get_args(OPENID_NS)) end def test_replay # Don't validate the same response twice. # # From "Checking the Nonce":: # # When using "check_authentication", the OP MUST ensure that an # assertion has not yet been accepted with the same value for # "openid.response_nonce". # # In this implementation, the assoc_handle is only valid once. # And nonces are a signed component of the message, so they can't # be used with another handle without breaking the sig. r = @request.answer(@signatory) r = @request.answer(@signatory) assert_equal({'is_valid' => 'false'}, r.fields.get_args(OPENID_NS)) end def test_invalidatehandle @request.invalidate_handle = "bogusHandle" r = @request.answer(@signatory) assert_equal(r.fields.get_args(OPENID_NS), {'is_valid' => 'true', 'invalidate_handle' => "bogusHandle"}) assert_equal(r.request, @request) end def test_invalidatehandleNo assoc_handle = 'goodhandle' @signatory.assocs << [false, 'goodhandle'] @request.invalidate_handle = assoc_handle r = @request.answer(@signatory) assert_equal(r.fields.get_args(OPENID_NS), {'is_valid' => 'true'}) end end class TestAssociate < Minitest::Test # TODO: test DH with non-default values for modulus and gen. # (important to do because we actually had it broken for a while.) def setup @request = Server::AssociateRequest.from_message(Message.from_post_args({})) @store = Store::Memory.new() @signatory = Server::Signatory.new(@store) end def test_dhSHA1 @assoc = @signatory.create_association(false, 'HMAC-SHA1') consumer_dh = DiffieHellman.from_defaults() cpub = consumer_dh.public server_dh = DiffieHellman.from_defaults() session = Server::DiffieHellmanSHA1ServerSession.new(server_dh, cpub) @request = Server::AssociateRequest.new(session, 'HMAC-SHA1') @request.message = Message.new(OPENID2_NS) response = @request.answer(@assoc) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call("assoc_type"), "HMAC-SHA1") assert_equal(rfg.call("assoc_handle"), @assoc.handle) assert(!rfg.call("mac_key")) assert_equal(rfg.call("session_type"), "DH-SHA1") assert(rfg.call("enc_mac_key")) assert(rfg.call("dh_server_public")) enc_key = Util.from_base64(rfg.call("enc_mac_key")) spub = CryptUtil.base64_to_num(rfg.call("dh_server_public")) secret = consumer_dh.xor_secret(CryptUtil.method('sha1'), spub, enc_key) assert_equal(secret, @assoc.secret) end def test_dhSHA256 @assoc = @signatory.create_association(false, 'HMAC-SHA256') consumer_dh = DiffieHellman.from_defaults() cpub = consumer_dh.public server_dh = DiffieHellman.from_defaults() session = Server::DiffieHellmanSHA256ServerSession.new(server_dh, cpub) @request = Server::AssociateRequest.new(session, 'HMAC-SHA256') @request.message = Message.new(OPENID2_NS) response = @request.answer(@assoc) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call("assoc_type"), "HMAC-SHA256") assert_equal(rfg.call("assoc_handle"), @assoc.handle) assert(!rfg.call("mac_key")) assert_equal(rfg.call("session_type"), "DH-SHA256") assert(rfg.call("enc_mac_key")) assert(rfg.call("dh_server_public")) enc_key = Util.from_base64(rfg.call("enc_mac_key")) spub = CryptUtil.base64_to_num(rfg.call("dh_server_public")) secret = consumer_dh.xor_secret(CryptUtil.method('sha256'), spub, enc_key) assert_equal(secret, @assoc.secret) end def test_protoError256 s256_session = Consumer::DiffieHellmanSHA256Session.new() invalid_s256 = {'openid.assoc_type' => 'HMAC-SHA1', 'openid.session_type' => 'DH-SHA256',} invalid_s256.merge!(s256_session.get_request()) invalid_s256_2 = {'openid.assoc_type' => 'MONKEY-PIRATE', 'openid.session_type' => 'DH-SHA256',} invalid_s256_2.merge!(s256_session.get_request()) bad_request_argss = [ invalid_s256, invalid_s256_2, ] bad_request_argss.each { |request_args| message = Message.from_post_args(request_args) assert_raises(Server::ProtocolError) { Server::AssociateRequest.from_message(message) } } end def test_protoError s1_session = Consumer::DiffieHellmanSHA1Session.new() invalid_s1 = {'openid.assoc_type' => 'HMAC-SHA256', 'openid.session_type' => 'DH-SHA1',} invalid_s1.merge!(s1_session.get_request()) invalid_s1_2 = {'openid.assoc_type' => 'ROBOT-NINJA', 'openid.session_type' => 'DH-SHA1',} invalid_s1_2.merge!(s1_session.get_request()) bad_request_argss = [ {'openid.assoc_type' => 'Wha?'}, invalid_s1, invalid_s1_2, ] bad_request_argss.each { |request_args| message = Message.from_post_args(request_args) assert_raises(Server::ProtocolError) { Server::AssociateRequest.from_message(message) } } end def test_protoErrorFields contact = 'user@example.invalid' reference = 'Trac ticket number MAX_INT' error = 'poltergeist' openid1_args = { 'openid.identitiy' => 'invalid', 'openid.mode' => 'checkid_setup', } openid2_args = openid1_args.dup openid2_args.merge!({'openid.ns' => OPENID2_NS}) # Check presence of optional fields in both protocol versions openid1_msg = Message.from_post_args(openid1_args) p = Server::ProtocolError.new(openid1_msg, error, reference, contact) reply = p.to_message() assert_equal(reply.get_arg(OPENID_NS, 'reference'), reference) assert_equal(reply.get_arg(OPENID_NS, 'contact'), contact) openid2_msg = Message.from_post_args(openid2_args) p = Server::ProtocolError.new(openid2_msg, error, reference, contact) reply = p.to_message() assert_equal(reply.get_arg(OPENID_NS, 'reference'), reference) assert_equal(reply.get_arg(OPENID_NS, 'contact'), contact) end def failUnlessExpiresInMatches(msg, expected_expires_in) expires_in_str = msg.get_arg(OPENID_NS, 'expires_in', NO_DEFAULT) expires_in = expires_in_str.to_i # Slop is necessary because the tests can sometimes get run # right on a second boundary slop = 1 # second difference = expected_expires_in - expires_in error_message = sprintf('"expires_in" value not within %s of expected: ' + 'expected=%s, actual=%s', slop, expected_expires_in, expires_in) assert((0 <= difference and difference <= slop), error_message) end def test_plaintext @assoc = @signatory.create_association(false, 'HMAC-SHA1') response = @request.answer(@assoc) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call("assoc_type"), "HMAC-SHA1") assert_equal(rfg.call("assoc_handle"), @assoc.handle) failUnlessExpiresInMatches(response.fields, @signatory.secret_lifetime) assert_equal( rfg.call("mac_key"), Util.to_base64(@assoc.secret)) assert(!rfg.call("session_type")) assert(!rfg.call("enc_mac_key")) assert(!rfg.call("dh_server_public")) end def test_plaintext_v2 # The main difference between this and the v1 test is that # session_type is always returned in v2. args = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'associate', 'openid.assoc_type' => 'HMAC-SHA1', 'openid.session_type' => 'no-encryption', } @request = Server::AssociateRequest.from_message( Message.from_post_args(args)) assert(!@request.message.is_openid1()) @assoc = @signatory.create_association(false, 'HMAC-SHA1') response = @request.answer(@assoc) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call("assoc_type"), "HMAC-SHA1") assert_equal(rfg.call("assoc_handle"), @assoc.handle) failUnlessExpiresInMatches( response.fields, @signatory.secret_lifetime) assert_equal( rfg.call("mac_key"), Util.to_base64(@assoc.secret)) assert_equal(rfg.call("session_type"), "no-encryption") assert(!rfg.call("enc_mac_key")) assert(!rfg.call("dh_server_public")) end def test_plaintext256 @assoc = @signatory.create_association(false, 'HMAC-SHA256') response = @request.answer(@assoc) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call("assoc_type"), "HMAC-SHA1") assert_equal(rfg.call("assoc_handle"), @assoc.handle) failUnlessExpiresInMatches( response.fields, @signatory.secret_lifetime) assert_equal( rfg.call("mac_key"), Util.to_base64(@assoc.secret)) assert(!rfg.call("session_type")) assert(!rfg.call("enc_mac_key")) assert(!rfg.call("dh_server_public")) end def test_unsupportedPrefer allowed_assoc = 'COLD-PET-RAT' allowed_sess = 'FROG-BONES' message = 'This is a unit test' # Set an OpenID 2 message so answerUnsupported doesn't raise # ProtocolError. @request.message = Message.new(OPENID2_NS) response = @request.answer_unsupported(message, allowed_assoc, allowed_sess) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call('error_code'), 'unsupported-type') assert_equal(rfg.call('assoc_type'), allowed_assoc) assert_equal(rfg.call('error'), message) assert_equal(rfg.call('session_type'), allowed_sess) end def test_unsupported message = 'This is a unit test' # Set an OpenID 2 message so answerUnsupported doesn't raise # ProtocolError. @request.message = Message.new(OPENID2_NS) response = @request.answer_unsupported(message) rfg = lambda { |f| response.fields.get_arg(OPENID_NS, f) } assert_equal(rfg.call('error_code'), 'unsupported-type') assert_equal(rfg.call('assoc_type'), nil) assert_equal(rfg.call('error'), message) assert_equal(rfg.call('session_type'), nil) end def test_openid1_unsupported_explode # answer_unsupported on an associate request should explode if # the request was an OpenID 1 request. m = Message.new(OPENID1_NS) assert_raises(Server::ProtocolError) { @request.answer_unsupported(m) } end end class UnhandledError < Exception end class TestServer < Minitest::Test include TestUtil def setup @store = Store::Memory.new() @server = Server::Server.new(@store, "http://server.unittest/endpt") # catchlogs_setup() end def test_failed_dispatch request = Server::OpenIDRequest.new() request.mode = "monkeymode" request.message = Message.new(OPENID1_NS) assert_raises(RuntimeError) { @server.handle_request(request) } end def test_decode_request @server.decoder = BogusDecoder.new(@server) assert(@server.decode_request({}) == "BOGUS") end def test_encode_response @server.encoder = BogusEncoder.new assert(@server.encode_response(nil) == "BOGUS") end def test_dispatch @server.extend(InstanceDefExtension) @server.instance_def(:openid_monkeymode) do |request| raise UnhandledError end request = Server::OpenIDRequest.new() request.mode = "monkeymode" request.message = Message.new(OPENID1_NS) assert_raises(UnhandledError) { @server.handle_request(request) } end def test_associate request = Server::AssociateRequest.from_message(Message.from_post_args({})) response = @server.openid_associate(request) assert(response.fields.has_key?(OPENID_NS, "assoc_handle"), sprintf("No assoc_handle here: %s", response.fields.inspect)) end def test_associate2 # Associate when the server has no allowed association types # # Gives back an error with error_code and no fallback session or # assoc types. @server.negotiator.allowed_types = [] # Set an OpenID 2 message so answerUnsupported doesn't raise # ProtocolError. msg = Message.from_post_args({ 'openid.ns' => OPENID2_NS, 'openid.session_type' => 'no-encryption', }) request = Server::AssociateRequest.from_message(msg) response = @server.openid_associate(request) assert(response.fields.has_key?(OPENID_NS, "error")) assert(response.fields.has_key?(OPENID_NS, "error_code")) assert(!response.fields.has_key?(OPENID_NS, "assoc_handle")) assert(!response.fields.has_key?(OPENID_NS, "assoc_type")) assert(!response.fields.has_key?(OPENID_NS, "session_type")) end def test_associate3 # Request an assoc type that is not supported when there are # supported types. # # Should give back an error message with a fallback type. @server.negotiator.allowed_types = [['HMAC-SHA256', 'DH-SHA256']] msg = Message.from_post_args({ 'openid.ns' => OPENID2_NS, 'openid.session_type' => 'no-encryption', }) request = Server::AssociateRequest.from_message(msg) response = @server.openid_associate(request) assert(response.fields.has_key?(OPENID_NS, "error")) assert(response.fields.has_key?(OPENID_NS, "error_code")) assert(!response.fields.has_key?(OPENID_NS, "assoc_handle")) assert_equal(response.fields.get_arg(OPENID_NS, "assoc_type"), 'HMAC-SHA256') assert_equal(response.fields.get_arg(OPENID_NS, "session_type"), 'DH-SHA256') end def test_associate4 # DH-SHA256 association session @server.negotiator.allowed_types = [['HMAC-SHA256', 'DH-SHA256']] query = { 'openid.dh_consumer_public' => 'ALZgnx8N5Lgd7pCj8K86T/DDMFjJXSss1SKoLmxE72kJTzOtG6I2PaYrHX' + 'xku4jMQWSsGfLJxwCZ6280uYjUST/9NWmuAfcrBfmDHIBc3H8xh6RBnlXJ' + '1WxJY3jHd5k1/ZReyRZOxZTKdF/dnIqwF8ZXUwI6peV0TyS/K1fOfF/s', 'openid.assoc_type' => 'HMAC-SHA256', 'openid.session_type' => 'DH-SHA256', } message = Message.from_post_args(query) request = Server::AssociateRequest.from_message(message) response = @server.openid_associate(request) assert(response.fields.has_key?(OPENID_NS, "assoc_handle")) end def test_no_encryption_openid1 # Make sure no-encryption associate requests for OpenID 1 are # logged. assert_log_matches(/Continuing anyway./) { m = Message.from_openid_args({ 'session_type' => 'no-encryption', }) Server::AssociateRequest.from_message(m) } end def test_missingSessionTypeOpenID2 # Make sure session_type is required in OpenID 2 msg = Message.from_post_args({ 'openid.ns' => OPENID2_NS, }) assert_raises(Server::ProtocolError) { Server::AssociateRequest.from_message(msg) } end def test_checkAuth request = Server::CheckAuthRequest.new('arrrrrf', '0x3999', []) request.message = Message.new(OPENID2_NS) response = nil silence_logging { response = @server.openid_check_authentication(request) } assert(response.fields.has_key?(OPENID_NS, "is_valid")) end end class TestingRequest < Server::OpenIDRequest attr_accessor :assoc_handle, :namespace end class TestSignatory < Minitest::Test include TestUtil def setup @store = Store::Memory.new() @signatory = Server::Signatory.new(@store) @_dumb_key = @signatory.class._dumb_key @_normal_key = @signatory.class._normal_key # CatchLogs.setUp(self) end def test_get_association_nil assert_raises(ArgumentError) { @signatory.get_association(nil, false) } end def test_sign request = TestingRequest.new() assoc_handle = '{assoc}{lookatme}' @store.store_association( @_normal_key, Association.from_expires_in(60, assoc_handle, 'sekrit', 'HMAC-SHA1')) request.assoc_handle = assoc_handle request.namespace = OPENID1_NS response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'foo' => 'amsigned', 'bar' => 'notsigned', 'azu' => 'alsosigned', }) sresponse = @signatory.sign(response) assert_equal( sresponse.fields.get_arg(OPENID_NS, 'assoc_handle'), assoc_handle) assert_equal(sresponse.fields.get_arg(OPENID_NS, 'signed'), 'assoc_handle,azu,bar,foo,signed') assert(sresponse.fields.get_arg(OPENID_NS, 'sig')) # assert(!@messages, @messages) end def test_signDumb request = TestingRequest.new() request.assoc_handle = nil request.namespace = OPENID2_NS response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'foo' => 'amsigned', 'bar' => 'notsigned', 'azu' => 'alsosigned', 'ns' => OPENID2_NS, }) sresponse = @signatory.sign(response) assoc_handle = sresponse.fields.get_arg(OPENID_NS, 'assoc_handle') assert(assoc_handle) assoc = @signatory.get_association(assoc_handle, true) assert(assoc) assert_equal(sresponse.fields.get_arg(OPENID_NS, 'signed'), 'assoc_handle,azu,bar,foo,ns,signed') assert(sresponse.fields.get_arg(OPENID_NS, 'sig')) # assert(!@messages, @messages) end def test_signExpired # Sign a response to a message with an expired handle (using # invalidate_handle). # # From "Verifying with an Association": # # If an authentication request included an association handle # for an association between the OP and the Relying party, and # the OP no longer wishes to use that handle (because it has # expired or the secret has been compromised, for instance), # the OP will send a response that must be verified directly # with the OP, as specified in Section 11.3.2. In that # instance, the OP will include the field # "openid.invalidate_handle" set to the association handle # that the Relying Party included with the original request. request = TestingRequest.new() request.namespace = OPENID2_NS assoc_handle = '{assoc}{lookatme}' @store.store_association( @_normal_key, Association.from_expires_in(-10, assoc_handle, 'sekrit', 'HMAC-SHA1')) assert(@store.get_association(@_normal_key, assoc_handle)) request.assoc_handle = assoc_handle response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'foo' => 'amsigned', 'bar' => 'notsigned', 'azu' => 'alsosigned', }) sresponse = nil silence_logging { sresponse = @signatory.sign(response) } new_assoc_handle = sresponse.fields.get_arg(OPENID_NS, 'assoc_handle') assert(new_assoc_handle) assert(new_assoc_handle != assoc_handle) assert_equal( sresponse.fields.get_arg(OPENID_NS, 'invalidate_handle'), assoc_handle) assert_equal(sresponse.fields.get_arg(OPENID_NS, 'signed'), 'assoc_handle,azu,bar,foo,invalidate_handle,signed') assert(sresponse.fields.get_arg(OPENID_NS, 'sig')) # make sure the expired association is gone assert(!@store.get_association(@_normal_key, assoc_handle), "expired association is still retrievable.") # make sure the new key is a dumb mode association assert(@store.get_association(@_dumb_key, new_assoc_handle)) assert(!@store.get_association(@_normal_key, new_assoc_handle)) # assert(@messages) end def test_signInvalidHandle request = TestingRequest.new() request.namespace = OPENID2_NS assoc_handle = '{bogus-assoc}{notvalid}' request.assoc_handle = assoc_handle response = Server::OpenIDResponse.new(request) response.fields = Message.from_openid_args({ 'foo' => 'amsigned', 'bar' => 'notsigned', 'azu' => 'alsosigned', }) sresponse = @signatory.sign(response) new_assoc_handle = sresponse.fields.get_arg(OPENID_NS, 'assoc_handle') assert(new_assoc_handle) assert(new_assoc_handle != assoc_handle) assert_equal( sresponse.fields.get_arg(OPENID_NS, 'invalidate_handle'), assoc_handle) assert_equal( sresponse.fields.get_arg(OPENID_NS, 'signed'), 'assoc_handle,azu,bar,foo,invalidate_handle,signed') assert(sresponse.fields.get_arg(OPENID_NS, 'sig')) # make sure the new key is a dumb mode association assert(@store.get_association(@_dumb_key, new_assoc_handle)) assert(!@store.get_association(@_normal_key, new_assoc_handle)) # @failIf(@messages, @messages) end def test_verify assoc_handle = '{vroom}{zoom}' assoc = Association.from_expires_in( 60, assoc_handle, 'sekrit', 'HMAC-SHA1') @store.store_association(@_dumb_key, assoc) signed = Message.from_post_args({ 'openid.foo' => 'bar', 'openid.apple' => 'orange', 'openid.assoc_handle' => assoc_handle, 'openid.signed' => 'apple,assoc_handle,foo,signed', 'openid.sig' => 'uXoT1qm62/BB09Xbj98TQ8mlBco=', }) verified = @signatory.verify(assoc_handle, signed) assert(verified) # assert(!@messages, @messages) end def test_verifyBadSig assoc_handle = '{vroom}{zoom}' assoc = Association.from_expires_in( 60, assoc_handle, 'sekrit', 'HMAC-SHA1') @store.store_association(@_dumb_key, assoc) signed = Message.from_post_args({ 'openid.foo' => 'bar', 'openid.apple' => 'orange', 'openid.assoc_handle' => assoc_handle, 'openid.signed' => 'apple,assoc_handle,foo,signed', 'openid.sig' => 'uXoT1qm62/BB09Xbj98TQ8mlBco=BOGUS' }) verified = @signatory.verify(assoc_handle, signed) # @failIf(@messages, @messages) assert(!verified) end def test_verifyBadHandle assoc_handle = '{vroom}{zoom}' signed = Message.from_post_args({ 'foo' => 'bar', 'apple' => 'orange', 'openid.sig' => "Ylu0KcIR7PvNegB/K41KpnRgJl0=", }) verified = nil silence_logging { verified = @signatory.verify(assoc_handle, signed) } assert !verified end def test_verifyAssocMismatch # Attempt to validate sign-all message with a signed-list assoc. assoc_handle = '{vroom}{zoom}' assoc = Association.from_expires_in( 60, assoc_handle, 'sekrit', 'HMAC-SHA1') @store.store_association(@_dumb_key, assoc) signed = Message.from_post_args({ 'foo' => 'bar', 'apple' => 'orange', 'openid.sig' => "d71xlHtqnq98DonoSgoK/nD+QRM=", }) verified = nil silence_logging { verified = @signatory.verify(assoc_handle, signed) } assert !verified end def test_getAssoc assoc_handle = makeAssoc(true) assoc = @signatory.get_association(assoc_handle, true) assert assoc assert_equal assoc.handle, assoc_handle end def test_getAssocExpired assoc_handle = makeAssoc(true, -10) assoc = nil silence_logging { assoc = @signatory.get_association(assoc_handle, true) } assert !assoc end def test_getAssocInvalid ah = 'no-such-handle' silence_logging { assert_equal( @signatory.get_association(ah, false), nil) } # assert(!@messages, @messages) end def test_getAssocDumbVsNormal # getAssociation(dumb=False) cannot get a dumb assoc assoc_handle = makeAssoc(true) silence_logging { assert_equal( @signatory.get_association(assoc_handle, false), nil) } # @failIf(@messages, @messages) end def test_getAssocNormalVsDumb # getAssociation(dumb=True) cannot get a shared assoc # # From "Verifying Directly with the OpenID Provider":: # # An OP MUST NOT verify signatures for associations that have shared # MAC keys. assoc_handle = makeAssoc(false) silence_logging { assert_equal( @signatory.get_association(assoc_handle, true), nil) } # @failIf(@messages, @messages) end def test_createAssociation assoc = @signatory.create_association(false) silence_logging { assert(@signatory.get_association(assoc.handle, false)) } # @failIf(@messages, @messages) end def makeAssoc(dumb, lifetime=60) assoc_handle = '{bling}' assoc = Association.from_expires_in(lifetime, assoc_handle, 'sekrit', 'HMAC-SHA1') silence_logging { @store.store_association(((dumb and @_dumb_key) or @_normal_key), assoc) } return assoc_handle end def test_invalidate assoc_handle = '-squash-' assoc = Association.from_expires_in(60, assoc_handle, 'sekrit', 'HMAC-SHA1') silence_logging { @store.store_association(@_dumb_key, assoc) assoc = @signatory.get_association(assoc_handle, true) assert(assoc) assoc = @signatory.get_association(assoc_handle, true) assert(assoc) @signatory.invalidate(assoc_handle, true) assoc = @signatory.get_association(assoc_handle, true) assert(!assoc) } # @failIf(@messages, @messages) end end class RunthroughTestCase < Minitest::Test def setup @store = Store::Memory.new @server = Server::Server.new(@store, "http://example.com/openid/server") end def test_openid1_assoc_checkid assoc_args = {'openid.mode' => 'associate', 'openid.assoc_type' => 'HMAC-SHA1'} areq = @server.decode_request(assoc_args) aresp = @server.handle_request(areq) amess = aresp.fields assert(amess.is_openid1) ahandle = amess.get_arg(OPENID_NS, 'assoc_handle') assert(ahandle) assoc = @store.get_association('http://localhost/|normal', ahandle) assert(assoc.is_a?(Association)) checkid_args = {'openid.mode' => 'checkid_setup', 'openid.return_to' => 'http://example.com/openid/consumer', 'openid.assoc_handle' => ahandle, 'openid.identity' => 'http://foo.com/'} cireq = @server.decode_request(checkid_args) ciresp = cireq.answer(true) signed_resp = @server.signatory.sign(ciresp) assert_equal(assoc.get_message_signature(signed_resp.fields), signed_resp.fields.get_arg(OPENID_NS, 'sig')) assert(assoc.check_message_signature(signed_resp.fields)) end end end ruby-openid-2.7.0debian.orig/test/test_associationmanager.rb0000644000175000017500000007252512512544714023541 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "openid/consumer/associationmanager" require "openid/association" require "openid/dh" require "openid/util" require "openid/cryptutil" require "openid/message" require "openid/protocolerror" require "openid/store/memory" require "util" require "time" module OpenID class DHAssocSessionTest < Minitest::Test def test_sha1_get_request # Initialized without an explicit DH gets defaults sess = Consumer::DiffieHellmanSHA1Session.new assert_equal(['dh_consumer_public'], sess.get_request.keys) Util::from_base64(sess.get_request['dh_consumer_public']) end def test_sha1_get_request_custom_dh dh = DiffieHellman.new(1299721, 2) sess = Consumer::DiffieHellmanSHA1Session.new(dh) req = sess.get_request assert_equal(['dh_consumer_public', 'dh_modulus', 'dh_gen'].sort, req.keys.sort) assert_equal(dh.modulus, CryptUtil.base64_to_num(req['dh_modulus'])) assert_equal(dh.generator, CryptUtil.base64_to_num(req['dh_gen'])) Util::from_base64(req['dh_consumer_public']) end end module TestDiffieHellmanResponseParametersMixin def setup session_cls = self.class.session_cls # Pre-compute DH with small prime so tests run quickly. @server_dh = DiffieHellman.new(100389557, 2) @consumer_dh = DiffieHellman.new(100389557, 2) # base64(btwoc(g ^ xb mod p)) @dh_server_public = CryptUtil.num_to_base64(@server_dh.public) @secret = CryptUtil.random_string(session_cls.secret_size) enc_mac_key_unencoded = @server_dh.xor_secret(session_cls.hashfunc, @consumer_dh.public, @secret) @enc_mac_key = Util.to_base64(enc_mac_key_unencoded) @consumer_session = session_cls.new(@consumer_dh) @msg = Message.new(self.class.message_namespace) end def test_extract_secret @msg.set_arg(OPENID_NS, 'dh_server_public', @dh_server_public) @msg.set_arg(OPENID_NS, 'enc_mac_key', @enc_mac_key) extracted = @consumer_session.extract_secret(@msg) assert_equal(extracted, @secret) end def test_absent_serve_public @msg.set_arg(OPENID_NS, 'enc_mac_key', @enc_mac_key) assert_raises(Message::KeyNotFound) { @consumer_session.extract_secret(@msg) } end def test_absent_mac_key @msg.set_arg(OPENID_NS, 'dh_server_public', @dh_server_public) assert_raises(Message::KeyNotFound) { @consumer_session.extract_secret(@msg) } end def test_invalid_base64_public @msg.set_arg(OPENID_NS, 'dh_server_public', 'n o t b a s e 6 4.') @msg.set_arg(OPENID_NS, 'enc_mac_key', @enc_mac_key) assert_raises(ArgumentError) { @consumer_session.extract_secret(@msg) } end def test_invalid_base64_mac_key @msg.set_arg(OPENID_NS, 'dh_server_public', @dh_server_public) @msg.set_arg(OPENID_NS, 'enc_mac_key', 'n o t base 64') assert_raises(ArgumentError) { @consumer_session.extract_secret(@msg) } end end class TestConsumerOpenID1DHSHA1 < Minitest::Test include TestDiffieHellmanResponseParametersMixin class << self attr_reader :session_cls, :message_namespace end @session_cls = Consumer::DiffieHellmanSHA1Session @message_namespace = OPENID1_NS end class TestConsumerOpenID2DHSHA1 < Minitest::Test include TestDiffieHellmanResponseParametersMixin class << self attr_reader :session_cls, :message_namespace end @session_cls = Consumer::DiffieHellmanSHA1Session @message_namespace = OPENID2_NS end class TestConsumerOpenID2DHSHA256 < Minitest::Test include TestDiffieHellmanResponseParametersMixin class << self attr_reader :session_cls, :message_namespace end @session_cls = Consumer::DiffieHellmanSHA256Session @message_namespace = OPENID2_NS end class TestConsumerNoEncryptionSession < Minitest::Test def setup @sess = Consumer::NoEncryptionSession.new end def test_empty_request assert_equal(@sess.get_request, {}) end def test_get_secret secret = 'shhh!' * 4 mac_key = Util.to_base64(secret) msg = Message.from_openid_args({'mac_key' => mac_key}) assert_equal(secret, @sess.extract_secret(msg)) end end class TestCreateAssociationRequest < Minitest::Test def setup @server_url = 'http://invalid/' @assoc_manager = Consumer::AssociationManager.new(nil, @server_url) class << @assoc_manager def compatibility_mode=(val) @compatibility_mode = val end end @assoc_type = 'HMAC-SHA1' end def test_no_encryption_sends_type session_type = 'no-encryption' session, args = @assoc_manager.send(:create_associate_request, @assoc_type, session_type) assert(session.is_a?(Consumer::NoEncryptionSession)) expected = Message.from_openid_args( {'ns' => OPENID2_NS, 'session_type' => session_type, 'mode' => 'associate', 'assoc_type' => @assoc_type, }) assert_equal(expected, args) end def test_no_encryption_compatibility @assoc_manager.compatibility_mode = true session_type = 'no-encryption' session, args = @assoc_manager.send(:create_associate_request, @assoc_type, session_type) assert(session.is_a?(Consumer::NoEncryptionSession)) assert_equal(Message.from_openid_args({'mode' => 'associate', 'assoc_type' => @assoc_type, }), args) end def test_dh_sha1_compatibility @assoc_manager.compatibility_mode = true session_type = 'DH-SHA1' session, args = @assoc_manager.send(:create_associate_request, @assoc_type, session_type) assert(session.is_a?(Consumer::DiffieHellmanSHA1Session)) # This is a random base-64 value, so just check that it's # present. refute_nil(args.get_arg(OPENID1_NS, 'dh_consumer_public')) args.del_arg(OPENID1_NS, 'dh_consumer_public') # OK, session_type is set here and not for no-encryption # compatibility expected = Message.from_openid_args({'mode' => 'associate', 'session_type' => 'DH-SHA1', 'assoc_type' => @assoc_type, }) assert_equal(expected, args) end end class TestAssociationManagerExpiresIn < Minitest::Test def expires_in_msg(val) msg = Message.from_openid_args({'expires_in' => val}) Consumer::AssociationManager.extract_expires_in(msg) end def test_parse_fail ['', '-2', ' 1', ' ', '0x00', 'foosball', '1\n', '100,000,000,000', ].each do |x| assert_raises(ProtocolError) {expires_in_msg(x)} end end def test_parse ['0', '1', '1000', '9999999', '01', ].each do |n| assert_equal(n.to_i, expires_in_msg(n)) end end end class TestAssociationManagerCreateSession < Minitest::Test def test_invalid assert_raises(ArgumentError) { Consumer::AssociationManager.create_session('monkeys') } end def test_sha256 sess = Consumer::AssociationManager.create_session('DH-SHA256') assert(sess.is_a?(Consumer::DiffieHellmanSHA256Session)) end end module NegotiationTestMixin include TestUtil def mk_message(args) args['ns'] = @openid_ns Message.from_openid_args(args) end def call_negotiate(responses, negotiator=nil) store = nil compat = self.class::Compat assoc_manager = Consumer::AssociationManager.new(store, @server_url, compat, negotiator) class << assoc_manager attr_accessor :responses def request_association(assoc_type, session_type) m = @responses.shift if m.is_a?(Message) raise ServerError.from_message(m) else return m end end end assoc_manager.responses = responses assoc_manager.negotiate_association end end # Test the session type negotiation behavior of an OpenID 2 # consumer. class TestOpenID2SessionNegotiation < Minitest::Test include NegotiationTestMixin Compat = false def setup @server_url = 'http://invalid/' @openid_ns = OPENID2_NS end # Test the case where the response to an associate request is a # server error or is otherwise undecipherable. def test_bad_response assert_log_matches('Server error when requesting an association') { assert_equal(call_negotiate([mk_message({})]), nil) } end # Test the case where the association type (assoc_type) returned # in an unsupported-type response is absent. def test_empty_assoc_type msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'session_type' => 'new-session-type', }) assert_log_matches('Unsupported association type', "Server #{@server_url} responded with unsupported "\ "association session but did not supply a fallback." ) { assert_equal(call_negotiate([msg]), nil) } end # Test the case where the session type (session_type) returned # in an unsupported-type response is absent. def test_empty_session_type msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'new-assoc-type', }) assert_log_matches('Unsupported association type', "Server #{@server_url} responded with unsupported "\ "association session but did not supply a fallback." ) { assert_equal(call_negotiate([msg]), nil) } end # Test the case where an unsupported-type response specifies a # preferred (assoc_type, session_type) combination that is not # allowed by the consumer's SessionNegotiator. def test_not_allowed negotiator = AssociationNegotiator.new([]) negotiator.instance_eval{ @allowed_types = [['assoc_bogus', 'session_bogus']] } msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'not-allowed', 'session_type' => 'not-allowed', }) assert_log_matches('Unsupported association type', 'Server sent unsupported session/association type:') { assert_equal(call_negotiate([msg], negotiator), nil) } end # Test the case where an unsupported-type response triggers a # retry to get an association with the new preferred type. def test_unsupported_with_retry msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'HMAC-SHA1', 'session_type' => 'DH-SHA1', }) assoc = Association.new('handle', 'secret', Time.now, 10000, 'HMAC-SHA1') assert_log_matches('Unsupported association type') { assert_equal(assoc, call_negotiate([msg, assoc])) } end # Test the case where an unsupported-typ response triggers a # retry, but the retry fails and nil is returned instead. def test_unsupported_with_retry_and_fail msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'HMAC-SHA1', 'session_type' => 'DH-SHA1', }) assert_log_matches('Unsupported association type', "Server #{@server_url} refused") { assert_equal(call_negotiate([msg, msg]), nil) } end # Test the valid case, wherein an association is returned on the # first attempt to get one. def test_valid assoc = Association.new('handle', 'secret', Time.now, 10000, 'HMAC-SHA1') assert_log_matches() { assert_equal(call_negotiate([assoc]), assoc) } end end # Tests for the OpenID 1 consumer association session behavior. See # the docs for TestOpenID2SessionNegotiation. Notice that this # class is not a subclass of the OpenID 2 tests. Instead, it uses # many of the same inputs but inspects the log messages logged with # oidutil.log. See the calls to self.failUnlessLogMatches. Some of # these tests pass openid2-style messages to the openid 1 # association processing logic to be sure it ignores the extra data. class TestOpenID1SessionNegotiation < Minitest::Test include NegotiationTestMixin Compat = true def setup @server_url = 'http://invalid/' @openid_ns = OPENID1_NS end def test_bad_response assert_log_matches('Server error when requesting an association') { response = call_negotiate([mk_message({})]) assert_equal(nil, response) } end def test_empty_assoc_type msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'session_type' => 'new-session-type', }) assert_log_matches('Server error when requesting an association') { response = call_negotiate([msg]) assert_equal(nil, response) } end def test_empty_session_type msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'new-assoc-type', }) assert_log_matches('Server error when requesting an association') { response = call_negotiate([msg]) assert_equal(nil, response) } end def test_not_allowed negotiator = AssociationNegotiator.new([]) negotiator.instance_eval{ @allowed_types = [['assoc_bogus', 'session_bogus']] } msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'not-allowed', 'session_type' => 'not-allowed', }) assert_log_matches('Server error when requesting an association') { response = call_negotiate([msg]) assert_equal(nil, response) } end def test_unsupported_with_retry msg = mk_message({'error' => 'Unsupported type', 'error_code' => 'unsupported-type', 'assoc_type' => 'HMAC-SHA1', 'session_type' => 'DH-SHA1', }) assoc = Association.new('handle', 'secret', Time.now, 10000, 'HMAC-SHA1') assert_log_matches('Server error when requesting an association') { response = call_negotiate([msg, assoc]) assert_equal(nil, response) } end def test_valid assoc = Association.new('handle', 'secret', Time.now, 10000, 'HMAC-SHA1') assert_log_matches() { response = call_negotiate([assoc]) assert_equal(assoc, response) } end end class TestExtractAssociation < Minitest::Test include ProtocolErrorMixin # An OpenID associate response (without the namespace) DEFAULTS = { 'expires_in' => '1000', 'assoc_handle' => 'a handle', 'assoc_type' => 'a type', 'session_type' => 'a session type', } def setup @assoc_manager = Consumer::AssociationManager.new(nil, nil) end # Make tests that ensure that an association response that is # missing required fields will raise an Message::KeyNotFound. # # According to 'Association Session Response' subsection 'Common # Response Parameters', the following fields are required for # OpenID 2.0: # # * ns # * session_type # * assoc_handle # * assoc_type # * expires_in # # In OpenID 1, everything except 'session_type' and 'ns' are # required. MISSING_FIELD_SETS = ([["no_fields", []]] + (DEFAULTS.keys.map do |f| fields = DEFAULTS.keys fields.delete(f) ["missing_#{f}", fields] end) ) [OPENID1_NS, OPENID2_NS].each do |ns| MISSING_FIELD_SETS.each do |name, fields| # OpenID 1 is allowed to be missing session_type if ns != OPENID1_NS and name != 'missing_session_type' test = lambda do msg = Message.new(ns) fields.each do |field| msg.set_arg(ns, field, DEFAULTS[field]) end assert_raises(Message::KeyNotFound) do @assoc_manager.send(:extract_association, msg, nil) end end define_method("test_#{name}", test) end end end # assert that extracting a response that contains the given # response session type when the request was made for the given # request session type will raise a ProtocolError indicating # session type mismatch def assert_session_mismatch(req_type, resp_type, ns) # Create an association session that has "req_type" as its # session_type and no allowed_assoc_types assoc_session_class = Class.new do @session_type = req_type def self.session_type @session_type end def self.allowed_assoc_types [] end end assoc_session = assoc_session_class.new # Build an OpenID 1 or 2 association response message that has # the specified association session type msg = Message.new(ns) msg.update_args(ns, DEFAULTS) msg.set_arg(ns, 'session_type', resp_type) # The request type and response type have been chosen to produce # a session type mismatch. assert_protocol_error('Session type mismatch') { @assoc_manager.send(:extract_association, msg, assoc_session) } end [['no-encryption', '', OPENID2_NS], ['DH-SHA1', 'no-encryption', OPENID2_NS], ['DH-SHA256', 'no-encryption', OPENID2_NS], ['no-encryption', 'DH-SHA1', OPENID2_NS], ['DH-SHA1', 'DH-SHA256', OPENID1_NS], ['DH-SHA256', 'DH-SHA1', OPENID1_NS], ['no-encryption', 'DH-SHA1', OPENID1_NS], ].each do |req_type, resp_type, ns| test = lambda { assert_session_mismatch(req_type, resp_type, ns) } name = "test_mismatch_req_#{req_type}_resp_#{resp_type}_#{ns}" define_method(name, test) end def test_openid1_no_encryption_fallback # A DH-SHA1 session assoc_session = Consumer::DiffieHellmanSHA1Session.new # An OpenID 1 no-encryption association response msg = Message.from_openid_args({ 'expires_in' => '1000', 'assoc_handle' => 'a handle', 'assoc_type' => 'HMAC-SHA1', 'mac_key' => 'X' * 20, }) # Should succeed assoc = @assoc_manager.send(:extract_association, msg, assoc_session) assert_equal('a handle', assoc.handle) assert_equal('HMAC-SHA1', assoc.assoc_type) assert(assoc.expires_in.between?(999, 1000)) assert('X' * 20, assoc.secret) end end class GetOpenIDSessionTypeTest < Minitest::Test include TestUtil SERVER_URL = 'http://invalid/' def do_test(expected_session_type, session_type_value) # Create a Message with just 'session_type' in it, since # that's all this function will use. 'session_type' may be # absent if it's set to None. args = {} if !session_type_value.nil? args['session_type'] = session_type_value end message = Message.from_openid_args(args) assert(message.is_openid1) assoc_manager = Consumer::AssociationManager.new(nil, SERVER_URL) actual_session_type = assoc_manager.send(:get_openid1_session_type, message) error_message = ("Returned session type parameter #{session_type_value}"\ "was expected to yield session type "\ "#{expected_session_type}, but yielded "\ "#{actual_session_type}") assert_equal(expected_session_type, actual_session_type, error_message) end [['nil', 'no-encryption', nil], ['empty', 'no-encryption', ''], ['dh_sha1', 'DH-SHA1', 'DH-SHA1'], ['dh_sha256', 'DH-SHA256', 'DH-SHA256'], ].each {|name, expected, input| # Define a test method that will check what session type will be # used if the OpenID 1 response to an associate call sets the # 'session_type' field to `session_type_value` test = lambda {assert_log_matches() { do_test(expected, input) } } define_method("test_#{name}", &test) } # This one's different because it expects log messages def test_explicit_no_encryption assert_log_matches("WARNING: #{SERVER_URL} sent 'no-encryption'"){ do_test('no-encryption', 'no-encryption') } end end class ExtractAssociationTest < Minitest::Test include ProtocolErrorMixin SERVER_URL = 'http://invalid/' def setup @session_type = 'testing-session' # This must something that works for Association::from_expires_in @assoc_type = 'HMAC-SHA1' @assoc_handle = 'testing-assoc-handle' # These arguments should all be valid @assoc_response = Message.from_openid_args({ 'expires_in' => '1000', 'assoc_handle' => @assoc_handle, 'assoc_type' => @assoc_type, 'session_type' => @session_type, 'ns' => OPENID2_NS, }) assoc_session_cls = Class.new do class << self attr_accessor :allowed_assoc_types, :session_type end attr_reader :extract_secret_called, :secret def initialize @extract_secret_called = false @secret = 'shhhhh!' end def extract_secret(_) @extract_secret_called = true @secret end end @assoc_session = assoc_session_cls.new @assoc_session.class.allowed_assoc_types = [@assoc_type] @assoc_session.class.session_type = @session_type @assoc_manager = Consumer::AssociationManager.new(nil, SERVER_URL) end def call_extract @assoc_manager.send(:extract_association, @assoc_response, @assoc_session) end # Handle a full successful association response def test_works_with_good_fields assoc = call_extract assert(@assoc_session.extract_secret_called) assert_equal(@assoc_session.secret, assoc.secret) assert_equal(1000, assoc.lifetime) assert_equal(@assoc_handle, assoc.handle) assert_equal(@assoc_type, assoc.assoc_type) end def test_bad_assoc_type # Make sure that the assoc type in the response is not valid # for the given session. @assoc_session.class.allowed_assoc_types = [] assert_protocol_error('Unsupported assoc_type for sess') {call_extract} end def test_bad_expires_in # Invalid value for expires_in should cause failure @assoc_response.set_arg(OPENID_NS, 'expires_in', 'forever') assert_protocol_error('Invalid expires_in') {call_extract} end end class TestExtractAssociationDiffieHellman < Minitest::Test include ProtocolErrorMixin SECRET = 'x' * 20 def setup @assoc_manager = Consumer::AssociationManager.new(nil, nil) end def setup_dh sess, _ = @assoc_manager.send(:create_associate_request, 'HMAC-SHA1', 'DH-SHA1') server_dh = DiffieHellman.new cons_dh = sess.instance_variable_get('@dh') enc_mac_key = server_dh.xor_secret(CryptUtil.method(:sha1), cons_dh.public, SECRET) server_resp = { 'dh_server_public' => CryptUtil.num_to_base64(server_dh.public), 'enc_mac_key' => Util.to_base64(enc_mac_key), 'assoc_type' => 'HMAC-SHA1', 'assoc_handle' => 'handle', 'expires_in' => '1000', 'session_type' => 'DH-SHA1', } if @assoc_manager.instance_variable_get(:@compatibility_mode) server_resp['ns'] = OPENID2_NS end return [sess, Message.from_openid_args(server_resp)] end def test_success sess, server_resp = setup_dh ret = @assoc_manager.send(:extract_association, server_resp, sess) assert(!ret.nil?) assert_equal(ret.assoc_type, 'HMAC-SHA1') assert_equal(ret.secret, SECRET) assert_equal(ret.handle, 'handle') assert_equal(ret.lifetime, 1000) end def test_openid2success # Use openid 1 type in endpoint so _setUpDH checks # compatibility mode state properly @assoc_manager.instance_variable_set('@compatibility_mode', true) test_success() end def test_bad_dh_values sess, server_resp = setup_dh server_resp.set_arg(OPENID_NS, 'enc_mac_key', '\x00\x00\x00') assert_protocol_error('Malformed response for') { @assoc_manager.send(:extract_association, server_resp, sess) } end end class TestAssocManagerGetAssociation < Minitest::Test include FetcherMixin include TestUtil attr_reader :negotiate_association def setup @server_url = 'http://invalid/' @store = Store::Memory.new @assoc_manager = Consumer::AssociationManager.new(@store, @server_url) @assoc_manager.extend(Const) @assoc = Association.new('handle', 'secret', Time.now, 10000, 'HMAC-SHA1') end def set_negotiate_response(assoc) @assoc_manager.const(:negotiate_association, assoc) end def test_not_in_store_no_response set_negotiate_response(nil) assert_equal(nil, @assoc_manager.get_association) end def test_not_in_store_negotiate_assoc # Not stored beforehand: stored_assoc = @store.get_association(@server_url, @assoc.handle) assert_equal(nil, stored_assoc) # Returned from associate call: set_negotiate_response(@assoc) assert_equal(@assoc, @assoc_manager.get_association) # It should have been stored: stored_assoc = @store.get_association(@server_url, @assoc.handle) assert_equal(@assoc, stored_assoc) end def test_in_store_no_response set_negotiate_response(nil) @store.store_association(@server_url, @assoc) assert_equal(@assoc, @assoc_manager.get_association) end def test_request_assoc_with_status_error fetcher_class = Class.new do define_method(:fetch) do |*args| MockResponse.new(500, '') end end with_fetcher(fetcher_class.new) do assert_log_matches('Got HTTP status error when requesting') { result = @assoc_manager.send(:request_association, 'HMAC-SHA1', 'no-encryption') assert(result.nil?) } end end end class TestAssocManagerRequestAssociation < Minitest::Test include FetcherMixin include TestUtil def setup @assoc_manager = Consumer::AssociationManager.new(nil, 'http://invalid/') @assoc_type = 'HMAC-SHA1' @session_type = 'no-encryption' @message = Message.new(OPENID2_NS) @message.update_args(OPENID_NS, { 'assoc_type' => @assoc_type, 'session_type' => @session_type, 'assoc_handle' => 'kaboodle', 'expires_in' => '1000', 'mac_key' => 'X' * 20, }) end def make_request kv = @message.to_kvform fetcher_class = Class.new do define_method(:fetch) do |*args| MockResponse.new(200, kv) end end with_fetcher(fetcher_class.new) do @assoc_manager.send(:request_association, @assoc_type, @session_type) end end # The association we get is from valid processing of our result, # and that no errors are raised def test_success assert_equal('kaboodle', make_request.handle) end # A missing parameter gets translated into a log message and # causes the method to return nil def test_missing_fields @message.del_arg(OPENID_NS, 'assoc_type') assert_log_matches('Missing required par') { assert_equal(nil, make_request) } end # A bad value results in a log message and causes the method to # return nil def test_protocol_error @message.set_arg(OPENID_NS, 'expires_in', 'goats') assert_log_matches('Protocol error processing') { assert_equal(nil, make_request) } end end end ruby-openid-2.7.0debian.orig/test/test_xrds.rb0000644000175000017500000001064412512544714020644 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'openid/yadis/xrds' module OpenID module Yadis module XRDSTestMixin include TestDataMixin XRD_FILE = 'valid-populated-xrds.xml' NOXRDS_FILE = 'not-xrds.xml' NOXRD_FILE = 'no-xrd.xml' XRDS_DATA_DIR = TEST_DATA_DIR.join('test_xrds') def read_xrds_data_file(filename) read_data_file(filename, false, XRDS_DATA_DIR) end end class ParseXRDSTestCase < Minitest::Test include XRDSTestMixin # Check that parsing succeeds at all. def test_parse result = Yadis.parseXRDS(read_xrds_data_file(XRD_FILE)) refute_nil result end def test_parse_no_xrds_xml xmldoc = read_xrds_data_file(NOXRDS_FILE) assert_raises(Yadis::XRDSError) { Yadis.parseXRDS(xmldoc) } end def test_parse_no_xrds_empty assert_raises(Yadis::XRDSError) { Yadis.parseXRDS('') } end def test_is_xrds isnt = REXML::Document.new(read_xrds_data_file(NOXRDS_FILE)) should_be = Yadis.parseXRDS(read_xrds_data_file(XRD_FILE)) assert_equal false, Yadis::is_xrds?(isnt) assert Yadis::is_xrds?(should_be) end end class GetYadisXRDTestCase < Minitest::Test include XRDSTestMixin # XXX: Test to make sure this really gets the _right_ XRD. def test_get_xrd doc = Yadis.parseXRDS(read_xrds_data_file(XRD_FILE)) result = Yadis::get_yadis_xrd(doc) refute_nil result assert_equal 'XRD', result.name assert_equal Yadis::XRD_NS_2_0, result.namespace end def test_no_xrd xmldoc = read_xrds_data_file(NOXRD_FILE) doc = Yadis.parseXRDS(xmldoc) assert_raises(Yadis::XRDSError) { Yadis.get_yadis_xrd(doc) } end end class EachServiceTestCase < Minitest::Test include XRDSTestMixin def test_get_xrd doc = Yadis.parseXRDS(read_xrds_data_file(XRD_FILE)) count = 0 result = Yadis::each_service(doc) { |e| assert_equal 'Service', e.name count += 1 } refute_nil result assert_equal 5, count end def test_no_xrd xmldoc = read_xrds_data_file(NOXRD_FILE) doc = Yadis.parseXRDS(xmldoc) assert_raises(Yadis::XRDSError) { Yadis.each_service(doc) } end def test_equal_j3h doc = Yadis.parseXRDS(read_xrds_data_file('=j3h.2007.11.14.xrds')) count = 0 result = Yadis::each_service(doc) { |e| assert_equal 'Service', e.name count += 1 } refute_nil result assert_equal 2, count end end # XXX: test prioSort! class ExpandServiceTestCase < Minitest::Test @@service_xml = < urn://foo urn://bar http://2.invalid/ http://0.invalid/ http://1.invalid/ END # XXX - not sorted! def test_expand_service service_element = REXML::Document.new(@@service_xml).root result = Yadis::expand_service(service_element) assert_equal 3, result.length types, uri, result_element = result[0] assert_same service_element, result_element assert_equal 'http://0.invalid/', uri assert_equal ['urn://foo', 'urn://bar'], types types, uri, result_element = result[1] assert_equal 'http://1.invalid/', uri types, uri, result_element = result[2] assert_equal 'http://2.invalid/', uri end end class PrioSortTestCase < Minitest::Test def new_uri(priority) e = REXML::Element.new("URI") e.add_attribute("priority", priority.to_s) unless e.nil? return e end def test_sorting l = [ e7 = new_uri(7), e1 = new_uri(1), e0 = new_uri(nil), e2 = new_uri(2), ] sorted = Yadis::prio_sort(l) assert_same e0, sorted[0] assert_same e1, sorted[1] assert_same e2, sorted[2] assert_same e7, sorted[3] end end class GetCanonicalIDTestCase < Minitest::Test include XRDSTestMixin def test_multisegment_xri xmldoc = Yadis.parseXRDS(read_xrds_data_file('subsegments.xrds')) Yadis.get_canonical_id('xri://=nishitani*masaki', xmldoc) end end end end ruby-openid-2.7.0debian.orig/test/test_trustroot.rb0000644000175000017500000000715212512544714021751 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'openid/trustroot' class TrustRootTest < Minitest::Test include OpenID::TestDataMixin def _test_sanity(case_, sanity, desc) tr = OpenID::TrustRoot::TrustRoot.parse(case_) if sanity == 'sane' assert !tr.nil? assert tr.sane?, [case_, desc].join(' ') assert OpenID::TrustRoot::TrustRoot.check_sanity(case_), [case_, desc].join(' ') elsif sanity == 'insane' assert !tr.sane?, [case_, desc].join(' ') assert !OpenID::TrustRoot::TrustRoot.check_sanity(case_), [case_, desc].join(' ') else assert tr.nil?, case_ end end def _test_match(trust_root, url, expected_match) tr = OpenID::TrustRoot::TrustRoot.parse(trust_root) actual_match = tr.validate_url(url) if expected_match assert actual_match, [trust_root, url].join(' ') assert OpenID::TrustRoot::TrustRoot.check_url(trust_root, url) else assert !actual_match, [expected_match, actual_match, trust_root, url].join(' ') assert !OpenID::TrustRoot::TrustRoot.check_url(trust_root, url) end end def test_trustroots data = read_data_file('trustroot.txt', false) parts = data.split('=' * 40 + "\n").collect { |i| i.strip() } assert(parts[0] == '') _, ph, pdat, mh, mdat = parts getTests(['bad', 'insane', 'sane'], ph, pdat).each { |tc| sanity, desc, case_ = tc _test_sanity(case_, sanity, desc) } getTests([true, false], mh, mdat).each { |tc| match, _, case_ = tc trust_root, url = case_.split() _test_match(trust_root, url, match) } end def getTests(grps, head, dat) tests = [] top = head.strip() gdat = dat.split('-' * 40 + "\n").collect { |i| i.strip() } assert gdat[0] == '' assert gdat.length == (grps.length * 2 + 1) i = 1 grps.each { |x| n, desc = gdat[i].split(': ') cases = gdat[i + 1].split("\n") assert(cases.length == n.to_i, "Number of cases differs from header count") cases.each { |case_| tests += [[x, top + ' - ' + desc, case_]] } i += 2 } return tests end def test_return_to_matches data = [ [[], nil, false], [[], "", false], [[], "http://bogus/return_to", false], [["http://bogus/"], nil, false], [["://broken/"], nil, false], [["://broken/"], "http://broken/", false], [["http://*.broken/"], "http://foo.broken/", false], [["http://x.broken/"], "http://foo.broken/", false], [["http://first/", "http://second/path/"], "http://second/?query=x", false], [["http://broken/"], "http://broken/", true], [["http://first/", "http://second/"], "http://second/?query=x", true], ] data.each { |case_| allowed_return_urls, return_to, expected_result = case_ actual_result = OpenID::TrustRoot::return_to_matches(allowed_return_urls, return_to) assert(expected_result == actual_result) } end def test_build_discovery_url data = [ ["http://foo.com/path", "http://foo.com/path"], ["http://foo.com/path?foo=bar", "http://foo.com/path?foo=bar"], ["http://*.bogus.com/path", "http://www.bogus.com/path"], ["http://*.bogus.com:122/path", "http://www.bogus.com:122/path"], ] data.each { |case_| trust_root, expected_disco_url = case_ tr = OpenID::TrustRoot::TrustRoot.parse(trust_root) actual_disco_url = tr.build_discovery_url() assert actual_disco_url == expected_disco_url } end end ruby-openid-2.7.0debian.orig/test/test_xri.rb0000644000175000017500000000310312512544714020456 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/yadis/xri' module OpenID module Yadis class XriDiscoveryTestCase < Minitest::Test def test_isXRI? assert_equal(:xri, XRI.identifier_scheme('=john.smith')) assert_equal(:xri, XRI.identifier_scheme('@smiths/john')) assert_equal(:xri, XRI.identifier_scheme('xri://=john')) assert_equal(:xri, XRI.identifier_scheme('@ootao*test1')) assert_equal(:uri, XRI.identifier_scheme('smoker.myopenid.com')) assert_equal(:uri, XRI.identifier_scheme('http://smoker.myopenid.com')) assert_equal(:uri, XRI.identifier_scheme('https://smoker.myopenid.com')) end end class XriEscapingTestCase < Minitest::Test def test_escaping_percents assert_equal('@example/abc%252Fd/ef', XRI.escape_for_iri('@example/abc%2Fd/ef')) end def test_escaping_xref # no escapes assert_equal('@example/foo/(@bar)', XRI.escape_for_iri('@example/foo/(@bar)')) # escape slashes assert_equal('@example/foo/(@bar%2Fbaz)', XRI.escape_for_iri('@example/foo/(@bar/baz)')) # escape query ? and fragment # assert_equal('@example/foo/(@baz%3Fp=q%23r)?i=j#k', XRI.escape_for_iri('@example/foo/(@baz?p=q#r)?i=j#k')) end end class XriTransformationTestCase < Minitest::Test def test_to_iri_normal assert_equal('xri://@example', XRI.to_iri_normal('@example')) end # iri_to_url: # various ucschar to hex end end end ruby-openid-2.7.0debian.orig/test/test_ui.rb0000644000175000017500000000503712512544714020301 0ustar sbadiasbadiarequire 'openid/extensions/ui' require 'openid/message' require 'openid/server' require 'minitest/autorun' module OpenID module UITest class UIRequestTestCase < Minitest::Test def setup @req = UI::Request.new end def test_construct assert_nil @req.mode assert_nil @req.icon assert_nil @req.lang assert_equal 'ui', @req.ns_alias req2 = UI::Request.new("popup", true, "ja-JP") assert_equal "popup", req2.mode assert_equal true, req2.icon assert_equal "ja-JP", req2.lang end def test_add_mode @req.mode = "popup" assert_equal "popup", @req.mode end def test_add_icon @req.icon = true assert_equal true, @req.icon end def test_add_lang @req.lang = "ja-JP" assert_equal "ja-JP", @req.lang end def test_get_extension_args assert_equal({}, @req.get_extension_args) @req.mode = "popup" assert_equal({'mode' => 'popup'}, @req.get_extension_args) @req.icon = true assert_equal({'mode' => 'popup', 'icon' => true}, @req.get_extension_args) @req.lang = "ja-JP" assert_equal({'mode' => 'popup', 'icon' => true, 'lang' => 'ja-JP'}, @req.get_extension_args) end def test_parse_extension_args args = {'mode' => 'popup', 'icon' => true, 'lang' => 'ja-JP'} @req.parse_extension_args args assert_equal "popup", @req.mode assert_equal true, @req.icon assert_equal "ja-JP", @req.lang end def test_parse_extension_args_empty @req.parse_extension_args({}) assert_nil @req.mode assert_nil @req.icon assert_nil @req.lang end def test_from_openid_request openid_req_msg = Message.from_openid_args( 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'ns.ui' => UI::NS_URI, 'ui.mode' => 'popup', 'ui.icon' => true, 'ui.lang' => 'ja-JP' ) oid_req = Server::OpenIDRequest.new oid_req.message = openid_req_msg req = UI::Request.from_openid_request oid_req assert_equal "popup", req.mode assert_equal true, req.icon assert_equal "ja-JP", req.lang end def test_from_openid_request_no_ui_params message = Message.new openid_req = Server::OpenIDRequest.new openid_req.message = message ui_req = UI::Request.from_openid_request openid_req assert ui_req.nil? end end end end ruby-openid-2.7.0debian.orig/test/test_stores.rb0000644000175000017500000002314412512544714021202 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/store/interface' require 'openid/store/filesystem' require 'openid/store/memcache' 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 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, 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) ret_assoc = @store.get_association(server_url, nil) unexpected = [assoc2.handle, assoc3.handle] assert ret_assoc.nil? || !unexpected.member?(ret_assoc.handle) _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) end def test_assoc_cleanup 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 server_url "http://www.myopenid.com/openid" end def test_nonce [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") } end def test_nonce_cleanup 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 @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 < Minitest::Test 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 < Minitest::Test include StoreTestCase def setup @store = Memory.new end end begin ::TESTING_MEMCACHE rescue NameError else class MemcacheStoreTestCase < Minitest::Test include StoreTestCase def setup store_uniq = OpenID::CryptUtil.random_string(6, "0123456789") store_namespace = "openid-store-#{store_uniq}:" @store = Memcache.new(::TESTING_MEMCACHE, store_namespace) end def test_nonce_cleanup end def test_assoc_cleanup end end end class AbstractStoreTestCase < Minitest::Test 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_raises(NotImplementedError) { abc.store_association(server_url, association) } assert_raises(NotImplementedError) { abc.get_association(server_url) } assert_raises(NotImplementedError) { abc.remove_association(server_url, association.handle) } assert_raises(NotImplementedError) { abc.use_nonce(server_url, Time.now.to_i, "foo") } assert_raises(NotImplementedError) { abc.cleanup_nonces() } assert_raises(NotImplementedError) { abc.cleanup_associations() } assert_raises(NotImplementedError) { abc.cleanup() } end end end end ruby-openid-2.7.0debian.orig/test/test_openid_yadis.rb0000644000175000017500000001132612512544714022331 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/consumer/discovery' require 'openid/yadis/services' module OpenID XRDS_BOILERPLATE = < %s EOF def self.mkXRDS(services) return sprintf(XRDS_BOILERPLATE, services) end def self.mkService(uris=nil, type_uris=nil, local_id=nil, dent=" ") chunks = [dent, "\n"] dent2 = dent + " " if type_uris type_uris.each { |type_uri| chunks += [dent2 + "", type_uri, "\n"] } end if uris uris.each { |uri| if uri.is_a?(Array) uri, prio = uri else prio = nil end chunks += [dent2, "", uri, "\n"] } end if local_id chunks += [dent2, "", local_id, "\n"] end chunks += [dent, "\n"] return chunks.join("") end # Different sets of server URLs for use in the URI tag SERVER_URL_OPTIONS = [ [], # This case should not generate an endpoint object ['http://server.url/'], ['https://server.url/'], ['https://server.url/', 'http://server.url/'], ['https://server.url/', 'http://server.url/', 'http://example.server.url/'], ] # Used for generating test data def OpenID.subsets(l) subsets_list = [[]] l.each { |x| subsets_list += subsets_list.collect { |t| [x] + t } } return subsets_list end # A couple of example extension type URIs. These are not at all # official, but are just here for testing. EXT_TYPES = [ 'http://janrain.com/extension/blah', 'http://openid.net/sreg/1.0', ] # Range of valid Delegate tag values for generating test data LOCAL_ID_OPTIONS = [ nil, 'http://vanity.domain/', 'https://somewhere/yadis/', ] class OpenIDYadisTest def initialize(uris, type_uris, local_id) super() @uris = uris @type_uris = type_uris @local_id = local_id @yadis_url = 'http://unit.test/' # Create an XRDS document to parse services = OpenID.mkService(@uris, @type_uris, @local_id) @xrds = OpenID.mkXRDS(services) end def runTest(testcase) # Parse into endpoint objects that we will check endpoints = Yadis.apply_filter(@yadis_url, @xrds, OpenIDServiceEndpoint) # make sure there are the same number of endpoints as URIs. This # assumes that the type_uris contains at least one OpenID type. testcase.assert_equal(@uris.length, endpoints.length) # So that we can check equality on the endpoint types type_uris = @type_uris.dup type_uris.sort! seen_uris = [] endpoints.each { |endpoint| seen_uris << endpoint.server_url # All endpoints will have same yadis_url testcase.assert_equal(@yadis_url, endpoint.claimed_id) # and local_id testcase.assert_equal(@local_id, endpoint.local_id) # and types actual_types = endpoint.type_uris.dup actual_types.sort! testcase.assert_equal(type_uris, actual_types, actual_types.inspect) } # So that they will compare equal, because we don't care what # order they are in seen_uris.sort! uris = @uris.dup uris.sort! # Make sure we saw all URIs, and saw each one once testcase.assert_equal(uris, seen_uris) end end class OpenIDYadisTests < Minitest::Test def test_openid_yadis data = [] # All valid combinations of Type tags that should produce an # OpenID endpoint type_uri_options = [] OpenID.subsets([OPENID_1_0_TYPE, OPENID_1_1_TYPE]).each { |ts| OpenID.subsets(EXT_TYPES).each { |exts| if !ts.empty? type_uri_options << exts + ts end } } # All combinations of valid URIs, Type URIs and Delegate tags SERVER_URL_OPTIONS.each { |uris| type_uri_options.each { |type_uris| LOCAL_ID_OPTIONS.each { |local_id| data << [uris, type_uris, local_id] } } } data.each { |args| t = OpenIDYadisTest.new(*args) t.runTest(self) } end end end ruby-openid-2.7.0debian.orig/test/test_pape.rb0000644000175000017500000002324712512544714020614 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/extensions/pape' require 'openid/message' require 'openid/server' require 'openid/consumer' module OpenID module PAPETest class PapeRequestTestCase < Minitest::Test def setup @req = PAPE::Request.new end def test_construct assert_equal([], @req.preferred_auth_policies) assert_equal(nil, @req.max_auth_age) assert_equal('pape', @req.ns_alias) req2 = PAPE::Request.new([PAPE::AUTH_MULTI_FACTOR], 1000) assert_equal([PAPE::AUTH_MULTI_FACTOR], req2.preferred_auth_policies) assert_equal(1000, req2.max_auth_age) end def test_add_policy_uri assert_equal([], @req.preferred_auth_policies) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) assert_equal([PAPE::AUTH_MULTI_FACTOR], @req.preferred_auth_policies) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) assert_equal([PAPE::AUTH_MULTI_FACTOR], @req.preferred_auth_policies) @req.add_policy_uri(PAPE::AUTH_PHISHING_RESISTANT) assert_equal([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT], @req.preferred_auth_policies) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) assert_equal([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT], @req.preferred_auth_policies) end def test_get_extension_args assert_equal({'preferred_auth_policies' => ''}, @req.get_extension_args) @req.add_policy_uri('http://uri') assert_equal({'preferred_auth_policies' => 'http://uri'}, @req.get_extension_args) @req.add_policy_uri('http://zig') assert_equal({'preferred_auth_policies' => 'http://uri http://zig'}, @req.get_extension_args) @req.max_auth_age = 789 assert_equal({'preferred_auth_policies' => 'http://uri http://zig', 'max_auth_age' => '789'}, @req.get_extension_args) end def test_parse_extension_args args = {'preferred_auth_policies' => 'http://foo http://bar', 'max_auth_age' => '9'} @req.parse_extension_args(args) assert_equal(9, @req.max_auth_age) assert_equal(['http://foo','http://bar'], @req.preferred_auth_policies) end def test_parse_extension_args_empty @req.parse_extension_args({}) assert_equal(nil, @req.max_auth_age) assert_equal([], @req.preferred_auth_policies) end def test_from_openid_request openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'ns.pape' => PAPE::NS_URI, 'pape.preferred_auth_policies' => [PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT].join(' '), 'pape.max_auth_age' => '5476' }) oid_req = Server::OpenIDRequest.new oid_req.message = openid_req_msg req = PAPE::Request.from_openid_request(oid_req) assert_equal([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT], req.preferred_auth_policies) assert_equal(5476, req.max_auth_age) end def test_from_openid_request_no_pape message = Message.new openid_req = Server::OpenIDRequest.new openid_req.message = message pape_req = PAPE::Request.from_openid_request(openid_req) assert(pape_req.nil?) end def test_preferred_types @req.add_policy_uri(PAPE::AUTH_PHISHING_RESISTANT) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) pt = @req.preferred_types([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_MULTI_FACTOR_PHYSICAL]) assert_equal([PAPE::AUTH_MULTI_FACTOR], pt) end end class DummySuccessResponse attr_accessor :message def initialize(message, signed_stuff) @message = message @signed_stuff = signed_stuff end def get_signed_ns(ns_uri) return @signed_stuff end end class PapeResponseTestCase < Minitest::Test def setup @req = PAPE::Response.new end def test_construct assert_equal([], @req.auth_policies) assert_equal(nil, @req.auth_time) assert_equal('pape', @req.ns_alias) assert_equal(nil, @req.nist_auth_level) req2 = PAPE::Response.new([PAPE::AUTH_MULTI_FACTOR], "1983-11-05T12:30:24Z", 3) assert_equal([PAPE::AUTH_MULTI_FACTOR], req2.auth_policies) assert_equal("1983-11-05T12:30:24Z", req2.auth_time) assert_equal(3, req2.nist_auth_level) end def test_add_policy_uri assert_equal([], @req.auth_policies) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) assert_equal([PAPE::AUTH_MULTI_FACTOR], @req.auth_policies) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) assert_equal([PAPE::AUTH_MULTI_FACTOR], @req.auth_policies) @req.add_policy_uri(PAPE::AUTH_PHISHING_RESISTANT) assert_equal([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT], @req.auth_policies) @req.add_policy_uri(PAPE::AUTH_MULTI_FACTOR) assert_equal([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT], @req.auth_policies) end def test_get_extension_args assert_equal({'auth_policies' => 'none'}, @req.get_extension_args) @req.add_policy_uri('http://uri') assert_equal({'auth_policies' => 'http://uri'}, @req.get_extension_args) @req.add_policy_uri('http://zig') assert_equal({'auth_policies' => 'http://uri http://zig'}, @req.get_extension_args) @req.auth_time = "1983-11-05T12:30:24Z" assert_equal({'auth_policies' => 'http://uri http://zig', 'auth_time' => "1983-11-05T12:30:24Z"}, @req.get_extension_args) @req.nist_auth_level = 3 assert_equal({'auth_policies' => 'http://uri http://zig', 'auth_time' => "1983-11-05T12:30:24Z", 'nist_auth_level' => '3'}, @req.get_extension_args) end def test_get_extension_args_error_auth_age @req.auth_time = "the beginning of time" assert_raises(ArgumentError) { @req.get_extension_args } end def test_get_extension_args_error_nist_auth_level @req.nist_auth_level = "high as a kite" assert_raises(ArgumentError) { @req.get_extension_args } @req.nist_auth_level = 5 assert_raises(ArgumentError) { @req.get_extension_args } @req.nist_auth_level = -1 assert_raises(ArgumentError) { @req.get_extension_args } end def test_parse_extension_args args = {'auth_policies' => 'http://foo http://bar', 'auth_time' => '1983-11-05T12:30:24Z'} @req.parse_extension_args(args) assert_equal('1983-11-05T12:30:24Z', @req.auth_time) assert_equal(['http://foo','http://bar'], @req.auth_policies) end def test_parse_extension_args_empty @req.parse_extension_args({}) assert_equal(nil, @req.auth_time) assert_equal([], @req.auth_policies) end def test_parse_extension_args_strict_bogus1 args = {'auth_policies' => 'http://foo http://bar', 'auth_time' => 'this one time'} assert_raises(ArgumentError) { @req.parse_extension_args(args, true) } end def test_parse_extension_args_strict_bogus2 args = {'auth_policies' => 'http://foo http://bar', 'auth_time' => '1983-11-05T12:30:24Z', 'nist_auth_level' => 'some'} assert_raises(ArgumentError) { @req.parse_extension_args(args, true) } end def test_parse_extension_args_strict_good args = {'auth_policies' => 'http://foo http://bar', 'auth_time' => '2007-10-11T05:25:18Z', 'nist_auth_level' => '0'} @req.parse_extension_args(args, true) assert_equal(['http://foo','http://bar'], @req.auth_policies) assert_equal('2007-10-11T05:25:18Z', @req.auth_time) assert_equal(0, @req.nist_auth_level) end def test_parse_extension_args_nostrict_bogus args = {'auth_policies' => 'http://foo http://bar', 'auth_time' => 'some time ago', 'nist_auth_level' => 'some'} @req.parse_extension_args(args) assert_equal(['http://foo','http://bar'], @req.auth_policies) assert_equal(nil, @req.auth_time) assert_equal(nil, @req.nist_auth_level) end def test_from_success_response openid_req_msg = Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.pape' => PAPE::NS_URI, 'pape.auth_policies' => [PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT].join(' '), 'pape.auth_time' => '1983-11-05T12:30:24Z' }) signed_stuff = { 'auth_policies' => [PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT].join(' '), 'auth_time' => '1983-11-05T12:30:24Z' } oid_req = DummySuccessResponse.new(openid_req_msg, signed_stuff) req = PAPE::Response.from_success_response(oid_req) assert_equal([PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT], req.auth_policies) assert_equal('1983-11-05T12:30:24Z', req.auth_time) end def test_from_success_response_unsigned openid_req_msg = Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.pape' => PAPE::NS_URI, 'pape.auth_policies' => [PAPE::AUTH_MULTI_FACTOR, PAPE::AUTH_PHISHING_RESISTANT].join(' '), 'pape.auth_time' => '1983-11-05T12:30:24Z' }) signed_stuff = {} endpoint = OpenIDServiceEndpoint.new oid_req = Consumer::SuccessResponse.new(endpoint, openid_req_msg, signed_stuff) req = PAPE::Response.from_success_response(oid_req) assert(req.nil?, req.inspect) end end end end ruby-openid-2.7.0debian.orig/test/test_accept.rb0000644000175000017500000001036112512544714021117 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'openid/yadis/accept' require 'openid/util' module OpenID class AcceptTest < Minitest::Test include TestDataMixin def getTestData() # Read the test data off of disk # # () -> [(int, str)] lines = read_data_file('accept.txt') line_no = 1 return lines.collect { |line| pair = [line_no, line] line_no += 1 pair } end def chunk(lines) # Return groups of lines separated by whitespace or comments # # [(int, str)] -> [[(int, str)]] chunks = [] chunk = [] lines.each { |lineno, line| stripped = line.strip() if (stripped == '') or stripped.start_with?('#') if chunk.length > 0 chunks << chunk chunk = [] end else chunk << [lineno, stripped] end } if chunk.length > 0 chunks << chunk end return chunks end def parseLines(chunk) # Take the given chunk of lines and turn it into a test data # dictionary # # [(int, str)] -> {str:(int, str)} items = {} chunk.each { |lineno, line| header, data = line.split(':', 2) header = header.downcase items[header] = [lineno, data.strip] } return items end def parseAvailable(available_text) # Parse an Available: line's data # # str -> [str] return available_text.split(',', -1).collect { |s| s.strip } end def parseExpected(expected_text) # Parse an Expected: line's data # # str -> [(str, float)] expected = [] if expected_text != '' expected_text.split(',', -1).each { |chunk| chunk = chunk.strip mtype, qstuff = chunk.split(';', -1) mtype = mtype.strip Util.assert(!mtype.index('/').nil?) qstuff = qstuff.strip q, qstr = qstuff.split('=', -1) Util.assert(q == 'q') qval = qstr.to_f expected << [mtype, qval] } end return expected end def test_accept_headers lines = getTestData() chunks = chunk(lines) data_sets = chunks.collect { |chunk| parseLines(chunk) } data_sets.each { |data| lnos = [] lno, header = data['accept'] lnos << lno lno, avail_data = data['available'] lnos << lno begin available = parseAvailable(avail_data) rescue print 'On line', lno raise end lno, exp_data = data['expected'] lnos << lno begin expected = parseExpected(exp_data) rescue print 'On line', lno raise end sprintf('MatchAcceptTest for lines %s', lnos) # Test: accepted = Yadis.parse_accept_header(header) actual = Yadis.match_types(accepted, available) assert_equal(expected, actual) assert_equal(Yadis.get_acceptable(header, available), expected.collect { |mtype, _| mtype }) } end def test_generate_accept_header # TODO: move this into a test case file and write parsing code # for it. # Form: [input_array, expected_header_string] [ # Empty input list [[], ""], # Content type name only; no q value [["test"], "test"], # q = 1.0 should be omitted from the header [[["test", 1.0]], "test"], # Test conversion of float to string [["test", ["with_q", 0.8]], "with_q; q=0.8, test"], # Allow string q values, too [["test", ["with_q_str", "0.7"]], "with_q_str; q=0.7, test"], # Test q values out of bounds [[["test", -1.0]], nil], [[["test", 1.1]], nil], # Test sorting of types by q value [[["middle", 0.5], ["min", 0.1], "max"], "min; q=0.1, middle; q=0.5, max"], ].each { |input, expected_header| if expected_header.nil? assert_raises(ArgumentError) { Yadis.generate_accept_header(*input) } else assert_equal(expected_header, Yadis.generate_accept_header(*input), [input, expected_header].inspect) end } end end end ruby-openid-2.7.0debian.orig/test/test_kvform.rb0000644000175000017500000001027612512544714021171 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/kvform' require 'openid/util' require 'util' include OpenID class KVFormTests < Minitest::Test include OpenID::TestUtil def test_kvdict [ # (kvform, parsed dictionary, expected warnings) ["", {}, 0], ["\n \n \n", {}, 0], ["college:harvey mudd\n", {"college" => "harvey mudd"}, 0], ["city:claremont\nstate:CA\n", {"city" => "claremont", "state" => "CA"}, 0], ["is_valid:true\ninvalidate_handle:{HMAC-SHA1:2398410938412093}\n", {"is_valid" => "true", "invalidate_handle" => "{HMAC-SHA1:2398410938412093}"}, 0], # Warnings from lines with no colon: ["x\n", {}, 1], ["x\nx\n", {}, 2], ["East is least\n", {}, 1], # But not from blank lines (because LJ generates them) ["x\n\n", {}, 1], # Warning from empty key [":\n", {''=>''}, 1], [":missing key\n", {''=>'missing key'}, 1], # Warnings from leading or trailing whitespace in key or value [" street:foothill blvd\n", {"street"=>"foothill blvd"}, 1], ["major: computer science\n", {"major"=>"computer science"}, 1], [" dorm : east \n", {"dorm"=>"east"}, 2], # Warnings from missing trailing newline ["e^(i*pi)+1:0", {"e^(i*pi)+1" => "0"}, 1], ["east:west\nnorth:south", {"east"=>"west", "north"=>"south"}, 1], ].each { |case_| _run_kvdictTest(case_) } end def _run_kvdictTest(case_) kv, dct, warnings = case_ d = nil d2 = nil assert_log_line_count(warnings) { # Convert KVForm to dict d = Util.kv_to_dict(kv) # Strict mode should raise KVFormError instead of logging # messages if warnings > 0 assert_raises(KVFormError) do Util.kv_to_seq(kv, true) end end # make sure it parses to expected dict assert_equal(dct, d) } # Convert back to KVForm and round-trip back to dict to make sure # that *** dict -> kv -> dict is identity. *** kv = Util.dict_to_kv(d) silence_logging { d2 = Util.kv_to_dict(kv) } assert_equal(d, d2) end def test_kvseq [ [[], "", 0], [[["openid", "useful"], ["a", "b"]], "openid:useful\na:b\n", 0], # Warnings about leading whitespace [[[" openid", "useful"], ["a", "b"]], " openid:useful\na:b\n", 2], # Warnings about leading and trailing whitespace [[[" openid ", " useful "], [" a ", " b "]], " openid : useful \n a : b \n", 8], # warnings about leading and trailing whitespace, but not about # internal whitespace. [[[" open id ", " use ful "], [" a ", " b "]], " open id : use ful \n a : b \n", 8], [[["foo", "bar"]], "foo:bar\n", 0], ].each { |case_| _run_kvseqTest(case_) } end def _cleanSeq(seq) # Create a new sequence by stripping whitespace from start and end # of each value of each pair seq.collect { |k, v| [k.strip(), v.strip()] } end def _run_kvseqTest(case_) seq, kvform, warnings = case_ assert_log_line_count(warnings) { # seq serializes to expected kvform actual = Util.seq_to_kv(seq) assert_equal(kvform, actual) assert actual.is_a?(String) # Strict mode should raise KVFormError instead of logging # messages if warnings > 0 assert_raises(KVFormError) do Util.seq_to_kv(seq, true) end end # Parse back to sequence. Expected to be unchanged, except # stripping whitespace from start and end of values # (i. e. ordering, case, and internal whitespace is preserved) seq = Util.kv_to_seq(actual) clean_seq = _cleanSeq(seq) assert_equal(seq, clean_seq) } end def test_kvexc [ [["openid", "use\nful"]], [["open\nid", "useful"]], [["open\nid", "use\nful"]], [["open:id", "useful"]], [["foo", "bar"], ["ba\n d", "seed"]], [["foo", "bar"], ["bad:", "seed"]], ].each { |case_| _run_kvexcTest(case_) } end def _run_kvexcTest(case_) seq = case_ assert_raises(KVFormError) do Util.seq_to_kv(seq) end end def test_convert assert_log_line_count(2) { result = Util.seq_to_kv([[1, 1]]) assert_equal(result, "1:1\n") } end end ruby-openid-2.7.0debian.orig/test/test_nonce.rb0000644000175000017500000000441712512544714020767 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/store/nonce' module OpenID class NonceTestCase < Minitest::Test NONCE_RE = /\A\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ/ def test_mk_nonce nonce = Nonce::mk_nonce assert(nonce.match(NONCE_RE)) assert(nonce.size == 26) end def test_mk_nonce_time nonce = Nonce::mk_nonce(0) assert(nonce.match(NONCE_RE)) assert(nonce.size == 26) assert(nonce.match(/^1970-01-01T00:00:00Z/)) end def test_split s = '1970-01-01T00:00:00Z' expected_t = 0 expected_salt = '' actual_t, actual_salt = Nonce::split_nonce(s) assert_equal(expected_t, actual_t) assert_equal(expected_salt, actual_salt) end def test_mk_split t = 42 nonce_str = Nonce::mk_nonce(t) assert(nonce_str.match(NONCE_RE)) at, salt = Nonce::split_nonce(nonce_str) assert_equal(6, salt.size) assert_equal(t, at) end def test_bad_split cases = [ '', '1970-01-01T00:00:00+1:00', '1969-01-01T00:00:00Z', '1970-00-01T00:00:00Z', '1970.01-01T00:00:00Z', 'Thu Sep 7 13:29:31 PDT 2006', 'monkeys', ] cases.each{|c| assert_raises(ArgumentError, c.inspect) { Nonce::split_nonce(c) } } end def test_check_timestamp cases = [ # exact, no allowed skew ['1970-01-01T00:00:00Z', 0, 0, true], # exact, large skew ['1970-01-01T00:00:00Z', 1000, 0, true], # no allowed skew, one second old ['1970-01-01T00:00:00Z', 0, 1, false], # many seconds old, outside of skew ['1970-01-01T00:00:00Z', 10, 50, false], # one second old, one second skew allowed ['1970-01-01T00:00:00Z', 1, 1, true], # One second in the future, one second skew allowed ['1970-01-01T00:00:02Z', 1, 1, true], # two seconds in the future, one second skew allowed ['1970-01-01T00:00:02Z', 1, 0, false], # malformed nonce string ['monkeys', 0, 0, false], ] cases.each{|c| (nonce_str, allowed_skew, now, expected) = c actual = Nonce::check_timestamp(nonce_str, allowed_skew, now) assert_equal(expected, actual, c.inspect) } end end end ruby-openid-2.7.0debian.orig/test/data/0000755000175000017500000000000012512544714017204 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/test/data/test1-discover.txt0000644000175000017500000000413212512544714022621 0ustar sbadiasbadiaequiv Status: 200 OK Content-Type: text/html Joe Schmoe's Homepage

Joe Schmoe's Homepage

Blah blah blah blah blah blah blah

header Status: 200 OK Content-Type: text/html YADIS_HEADER: URL_BASE/xrds Joe Schmoe's Homepage

Joe Schmoe's Homepage

Blah blah blah blah blah blah blah

xrds Status: 200 OK Content-Type: application/xrds+xml xrds_ctparam Status: 200 OK Content-Type: application/xrds+xml; charset=UTF8 xrds_ctcase Status: 200 OK Content-Type: appliCATION/XRDS+xml xrds_html Status: 200 OK Content-Type: text/html redir_equiv Status: 302 Found Content-Type: text/plain Location: URL_BASE/equiv You are presently being redirected. redir_header Status: 302 Found Content-Type: text/plain Location: URL_BASE/header You are presently being redirected. redir_xrds Status: 302 Found Content-Type: application/xrds+xml Location: URL_BASE/xrds redir_xrds_html Status: 302 Found Content-Type: text/plain Location: URL_BASE/xrds_html You are presently being redirected. redir_redir_equiv Status: 302 Found Content-Type: text/plain Location: URL_BASE/redir_equiv You are presently being redirected. lowercase_header Status: 200 OK Content-Type: text/html x-xrds-location: URL_BASE/xrds Joe Schmoe's Homepage

Joe Schmoe's Homepage

Blah blah blah blah blah blah blah

404_server_response Status: 404 Not Found EEk! 500_server_response Status: 500 Server error EEk! 201_server_response Status: 201 Created EEk! 404_with_header Status: 404 Not Found YADIS_HEADER: URL_BASE/xrds EEk! 404_with_meta Status: 404 Not Found Content-Type: text/html Joe Schmoe's Homepage

Joe Schmoe's Homepage

Blah blah blah blah blah blah blah

ruby-openid-2.7.0debian.orig/test/data/example-xrds.xml0000644000175000017500000000046312512544714022342 0ustar sbadiasbadia http://example.com/ http://www.openidenabled.com/ ruby-openid-2.7.0debian.orig/test/data/dh.txt0000644000175000017500000004301312512544714020341 0ustar sbadiasbadia130706940119084053627151828062879423433929180135817317038378606310097533503449582079984816816837125851552273641820339909167103200910805078308128174143174269944095368580519322913514764528012639683546377014716235962867583443566164615728897857285824741767070432119909660645255499710701356135207437699643611094585 139808169914464096465921128085565621767096724855516655439365028496569658038844954238931647642811548254956660405394116677296461848124300258439895306367561416289126854788101396379292925819850897858045772500578222021901631436550118958972312221974009238050517034542286574826081826542722270952769078386418682059418 91966407878983240112417790733941098492087186469785726449910011271065622315680646030230288265496017310433513856308693810812043160919214636748486185212617634222158204354206411031403206076739932806412551605172319515223573351072757800448643935018534945933808900467686115619932664888581913179496050117713298715475 88086484332488517006277516020842172054013692832175783214603951240851750819999098631851571207693874357651112736088114133607400684776234181681933311972926752846692615822043533641407510569745606256772455614745111122033229877596984718963046218854103292937700694160593653595134512369959987897086639788909618660591 94633950701209990078055218830969910271587805983595045023718108184189787131629772007048606080263109446462048743696369276578815611098215686598630889831104860221067872883514840819381234786050098278403321905311637820524177879167250981289318356078312300538871435101338967079907049912435983871847334104247675360099 136836393035803488129856151345450008294260680733328546556640578838845312279198933806383329293483852515700876505956362639881210101974254765087350842271260064592406308509078284840473735904755203614987286456952991025347168970462354352741159076541157478949094536405618626397435745496863324654768971213730622037771 24685127248019769965088146297942173464487677364928435784091685260262292485380918213538979925891771204729738138857126454465630594391449913947358655368215901119137728648638547728497517587701248406019427282237279437409508871300675355166059811431191200555457304463617727969228965042729205402243355816702436970430 103488011917988946858248200111251786178288940265978921633592888293430082248387786443813155999158786903216094876295371112716734481877806417714913656921169196196571699893360825510307056269738593971532017994987406325068886420548597161498019372380511676314312298122272401348856314619382867707981701472607230523868 116791045850880292989786005885944774698035781824784400772676299590038746153860847252706167458966356897309533614849402276819438194497464696186624618374179812548893947178936305721131565012344462048549467883494038577857638815386798694225798517783768606048713198211730870155881426709644960689953998714045816205549 25767875422998856261320430397505398614439586659207416236135894343577952114994718158163212134503751463610021489053571733974769536157057815413209619147486931502025658987681202196476489081257777148377685478756033509708349637895740799542063593586769082830323796978935454479273531157121440998804334199442003857410 75582226959658406842894734694860761896800153014775231713388264961517169436476322183886891849966756849783437334069692683523296295601533803799559985845105706728538458624387103621364117548643541824878550074680443708148686601108223917493525070861593238005735446708555769966855130921562955491250908613793521520082 51100990616369611694975829054222013346248289055987940844427061856603230021472379888102172458517294080775792439385531234808129302064303666640376750139242970123503857186428797403843206765926798353022284672682073397573130625177187185114726049347844460311761033584101482859992951420083621362870301150543916815123 22852401165908224137274273646590366934616265607879280260563022941455466297431255072303172649495519837876946233272420969249841381161312477263365567831938496555136366981954001163034914812189448922853839616662859772087929140818377228980710884492996109434435597500854043325062122184466315338260530734979159890875 35017410720028595029711778101507729481023945551700945988329114663345341120595162378885287946069695772429641825579528116641336456773227542256911497084242947904528367986325800537695079726856460817606404224094336361853766354225558025931211551975334149258299477750615397616908655079967952372222383056221992235704 37364490883518159794654045194678325635036705086417851509136183713863262621334636905291385255662750747808690129471989906644041585863034419130023070856805511017402434123099100618568335168939301014148587149578150068910141065808373976114927339040964292334109797421173369274978107389084873550233108940239410902552 40916262212189137562350357241447034318002130016858244002788189310078477605649010031339865625243230798681216437501833540185827501244378529230150467789369234869122179247196276164931090039290879808162629109742198951942358028123056268054775108592325500609335947248599688175189333996086475013450537086042387719925 42030470670714872936404499074069849778147578537708230270030877866700844337372497704027708080369726758812896818567830863540507961487472657570488625639077418109017434494794778542739932765561706796300920251933107517954265066804108669800167526425723377411855061131982689717887180411017924173629124764378241885274 124652439272864857598747946875599560379786580730218192165733924418687522301721706620565030507816884907589477351553268146177293719586287258662025940181301472851649975563004543250656807255226609296537922304346339513054316391667044301386950180277940536542183725690479451746977789001659540839582630251935163344393 33176766914206542084736303652243484580303865879984981189372762326078776390896986743451688462101732968104375838228070296418541745483112261133079756514082093269959937647525005374035326747696591842313517634077723301677759648869372517403529488493581781546743147639937580084065663597330159470577639629864369972900 67485835091897238609131069363014775606263390149204621594445803179810038685760826651889895397414961195533694176706808504447269558421955735607423135937153901140512527504198912146656610630396284977496295289999655140295415981288181545277299615922576281262872097567020980675200178329219970170480653040350512964539 131497983897702298481056962402569646971797912524360547236788650961059980711719600424210346263081838703940277066368168874781981151411096949736205282734026497995296147418292226818536168555712128736975034272678008697869326747592750850184857659420541708058277866000692785617873742438060271311159568468507825422571 5400380840349873337222394910303409203226429752629134721503171858543984393161548520471799318518954232197106728096866840965784563043721652790856860155702760027304915133166173298206604451826182024471262142046935060360564569939062438160049193241369468208458085699995573492688298015026628427440418009025072261296 83265103005695640943261961853521077357830295830250157593141844209296716788437615940096402365505416686459260302419338241462783388722843946886845478224048360927114533590583464979009731440049610985062455108831881153988321298531365779084012803908832525921630534096740755274371500276660832724874701671184539131864 141285570207910287798371174771658911045525474449663877845558585668334618068814605961306961485855329182957174312715910923324965889174835444049526313968571611940626279733302104955951067959291852710640374412577070764165811275030632465290729619533330733368808295932659463215921521905553936914975786500018720073003 68435028583616495789148116911096163791710022987677894923742899873596891423986951658100606742052014161171185231735413902875605720814417622409817842932759492013585936536452615480700628719795872201528559780249210820284350401473564919576289210869896327937002173624497942136329576506818749730506884927872345019446 134655528287263100540003157571441260698452262106680191153945271167894435782028803135774578949200580551016388918860856991026082917835209212892423567114480975540305860034439015788120390011692862968771136814777768281366591257663821495720134621172848947971117885754539770645621669309650476331439675400544167728223 97765390064836080322590528352647421920257073063706996347334558390461274981996865736612531330863478931481491964338380362350271734683183807511097331539820133036984271653285063355715726806139083282458695728902452215405696318402583540317419929113959816258829534543044153959951908676300847164682178008704099351835 92552521881196975294401505656851872247567784546370503402756239533783651371688190302773864319828182042605239246779598629409815474038541272600580320815319709309111399294952620375093803971373108792300726524826209329889463854451846561437729676142864421966497641824498079067929811613947148353921163336822026640804 145767094672933012300753301037546647564595762930138884463767054235112032706630891961371504668013023047595721138624016493638510710257541241706724342585654715468628355455898091951826598092812212209834746162089753649871544789379424903025374228231365026585872808685759231756517703720396301355299998059523896918448 116669462839999965355861187716880953863237226719689755457884414384663576662696981997535568446560375442532084973721539944428004043491468494548231348032618218312515409944970197902589794303562379864012797605284844016184274353252071642511293089390472576498394410829972525726474727579603392265177009323768966538608 34172517877854802711907683049441723730724885305592620486269966708379625109832852005775048584124451699198484092407720344962116726808090368739361658889584507734617844212547181476646725256303630128954338675520938806905779837227983648887192531356390902975904503218654196581612781227843742951241442641220856414232 126013077261793777773236390821108423367648447987653714614732477073177878509574051196587476846560696305938891953527959347566502332765820074506907037627115954790645652211088723122982633069089920979477728376746424256704724173255656757918995039125823421607024407307091796807227896314403153380323770001854211384322 9979624731056222925878866378063961280844793874828281622845276060532093809300121084179730782833657205171434732875093693074415298975346410131191865198158876447591891117577190438695367929923494177555818480377241891190442070100052523008290671797937772993634966511431668500154258765510857129203107386972819651767 76559085024395996164590986654274454741199399364851956129137304209855150918182685643729981600389513229011956888957763987167398150792454613751473654448162776379362213885827651020309844507723069713820393068520302223477225569348080362344052033711960892643036147232270133731530049660264526964146237693063093765111 18162696663677410793062235946366423954875282212790518677684260521370996677183041664345920941714064628111537529793170736292618705900247450994864220481135611781148410617609559050220262121494712903009168783279356915189941268264177631458029177102542745167475619936272581126346266816618866806564180995726437177435 63244550218824945129624987597134280916829928261688093445040235408899092619821698537312158783367974202557699994650667088974727356690181336666077506063310290098995215324552449858513870629176838494348632073938023916155113126203791709810160925798130199717340478393420816876665127594623142175853115698049952126277 4817943161362708117912118300716778687157593557807116683477307391846133734701449509121209661982298574607233039490570567781316652698287671086985501523197566560479906850423709894582834963398034434055472063156147829131181965140631257939036683622084290629927807369457311894970308590034407761706800045378158588657 61612160237840981966750225147965256022861527286827877531373888434780789812764688703260066154973576040405676432586962624922734102370509771313805122788566405984830112657060375568510809122230960988304085950306616401218206390412815884549481965750553137717475620505076144744211331973240555181377832337912951699135 36363324947629373144612372870171042343590861026293829791335153646774927623889458346817049419803031378037141773848560341251355283891019532059644644509836766167835557471311319194033709837770615526356168418160386395260066262292757953919140150454538786106958252854181965875293629955562111756775391296856504912587 86831561031659073326747216166881733513938228972332631084118628692228329095617884068498116676787029033973607066377816508795286358748076949738854520048303930186595481606562375516134920902325649683618195251332651685732712539073110524182134321873838204219194459231650917098791250048469346563303077080880339797744 26406869969418301728540993821409753036653370247174689204659006239823766914991146853283367848649039747728229875444327879875275718711878211919734397349994000106499628652960403076186651083084423734034070082770589453774926850920776427074440483233447839259180467805375782600203654373428926653730090468535611335253 100139935381469543084506312717977196291289016554846164338908226931204624582010530255955411615528804421371905642197394534614355186795223905217732992497673429554618838376065777445760355552020655667172127543653684405493978325270279321013143828897100500212200358450649158287605846102419527584313353072518101626851 92613116984760565837109105383781193800503303131143575169488835702472221039082994091847595094556327985517286288659598094631489552181233202387028607421487026032402972597880028640156629614572656967808446397456622178472130864873587747608262139844319805074476178618930354824943672367046477408898479503054125369731 30023391082615178562263328892343821010986429338255434046051061316154579824472412477397496718186615690433045030046315908170615910505869972621853946234911296439134838951047107272129711854649412919542407760508235711897489847951451200722151978578883748353566191421685659370090024401368356823252748749449302536931 31485815361342085113278193504381994806529237123359718043079410511224607873725611862217941085749929342777366642477711445011074784469367917758629403998067347054115844421430072631339788256386509261291675080191633908849638316409182455648806133048549359800886124554879661473112614246869101243501787363247762961784 114503770698890543429251666713050844656853278831559195214556474458830029271801818536133531843456707474500106283648085144619097572354066554819887152106174400667929098257361286338795493838820850475790977445807435511982704395422526800272723708548541616513134676140304653112325071112865020365664833601046215694089 76882090884790547431641385530818076533805072109483843307806375918023300052767710853172670987385376253156912268523505310624133905633437815297307463917718596711590885553760690350221265675690787249135345226947453988081566088302642706234126002514517416493192624887800567412565527886687096028028124049522890448168 15056463217273240496622619354104573042767532856243223052125822509781815362480522535564283485059790932505429110157271454207173426525345813426696743168079246510944969446574354255284952839036431873039487144279164893710061580467579842173706653409487110282515691099753380094215805485573768509475850463001549608836 52345178981230648108672997265819959243255047568833938156267924185186047373470984278294897653277996726416846430969793375429223610099546622112048283560483136389901514170116723365811871938630317974150540909650396429631704968748113009366339718498979597226137532343384889080245796447593572468846438769413505393967 32148494517199936472358017244372701214529606506776255341152991328091526865643069587953759877295255050519124541457805199596762210567333445908166076384465183589342153762720515477404466193879418014196727238972417616122646440870364200208488239778452378059236162633837824948613596114768455832408342040970780086 41095268619128788015767564971105114602454449306041732792746397800275041704886345704294273937217484580365505320134717320083763349380629342859670693445658118959823430378844830923452105707338162448974869312012791385772125813291388247857971218575518319578818336960572244046567099555399203328678654466958536663208 92166550199033418923713824997841892577149715275633481076285269142670107687867024550593869464613175882141630640739938334001211714884975032600306279287443909448541179109981755796752132502127330056736913454039526413284519137059580845856736918773597087836203497066909257930043736166431682872083389105176299181629 40049143661018504441607875135884755310012910557581028447435354354754245291878800571089144452035026644953322330676651798951447670184106450649737772686119714700743396359069052813433030118630105307022867200053964644574786137276428546712005171080129190959914708907200288299169344380390093918556722227705114244981 108159089972386282154772900619022507336076619354549601813179459338897131937353741544606392560724999980281424266891537298473163753022749859939445293926707568015958367188089915420630082556748668489756475027008449860889202622698060097015044886961901650857610841562477736791450080980702347705778074391774667412741 69905259478181995876884927656894491893594530150260951315109404530530357998889589977208787140430938039028941393673520799460431992051993157468616168400324834880926190141581037597526917869362292931957289043707855837933490285814769110495657056206391880865972389421774822461752702336812585852278453803972600333734 71821415380277072313878763768684432371552628204186742842154591000123020597011744840460964835414360968627162765288463383113375595799297552681618876474019263288277398833725479226930770694271622605114061622753165584075733358178384410640349907375170170910499615355511313349300918885560131539570707695789106185664 26945345439378873515011714350080059082081595419023056538696949766471272811362104837806324694947413603019863785876836706911406330379274553386254346050697348395574746891556054334903838949157798006141473389066020212044825140294048709654273698482867946522782450500680195477050110145664069582549935651920545151500 80313315938584480048642653013876614091607852535582224914294013785054094052454758327935781971746329853786568549510067442145637007308960551652864942042189241081946607011847245280773379099020221884296226818685556430275385068764313042226925852500883894269809033380734632866477789520106865758504064806906234130588 ruby-openid-2.7.0debian.orig/test/data/accept.txt0000644000175000017500000000647012512544714021213 0ustar sbadiasbadia# Accept: [Accept: header value from RFC2616, # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html] # Available: [whitespace-separated content types] # Expected: [Accept-header like list, containing the available content # types with their q-values] Accept: */* Available: text/plain Expected: text/plain; q=1.0 Accept: */* Available: text/plain, text/html Expected: text/plain; q=1.0, text/html; q=1.0 # The order matters Accept: */* Available: text/html, text/plain Expected: text/html; q=1.0, text/plain; q=1.0 Accept: text/*, */*; q=0.9 Available: text/plain, image/jpeg Expected: text/plain; q=1.0, image/jpeg; q=0.9 Accept: text/*, */*; q=0.9 Available: image/jpeg, text/plain Expected: text/plain; q=1.0, image/jpeg; q=0.9 # wildcard subtypes still reject differing main types Accept: text/* Available: image/jpeg, text/plain Expected: text/plain; q=1.0 Accept: text/html Available: text/html Expected: text/html; q=1.0 Accept: text/html, text/* Available: text/html Expected: text/html; q=1.0 Accept: text/html, text/* Available: text/plain, text/html Expected: text/plain; q=1.0, text/html; q=1.0 Accept: text/html, text/*; q=0.9 Available: text/plain, text/html Expected: text/html; q=1.0, text/plain; q=0.9 # If a more specific type has a higher q-value, then the higher value wins Accept: text/*; q=0.9, text/html Available: text/plain, text/html Expected: text/html; q=1.0, text/plain; q=0.9 Accept: */*, text/*; q=0.9, text/html; q=0.1 Available: text/plain, text/html, image/monkeys Expected: image/monkeys; q=1.0, text/plain; q=0.9, text/html; q=0.1 Accept: text/*, text/html; q=0 Available: text/html Expected: Accept: text/*, text/html; q=0 Available: text/html, text/plain Expected: text/plain; q=1.0 Accept: text/html Available: text/plain Expected: Accept: application/xrds+xml, text/html; q=0.9 Available: application/xrds+xml, text/html Expected: application/xrds+xml; q=1.0, text/html; q=0.9 Accept: application/xrds+xml, */*; q=0.9 Available: application/xrds+xml, text/html Expected: application/xrds+xml; q=1.0, text/html; q=0.9 Accept: application/xrds+xml, application/xhtml+xml; q=0.9, text/html; q=0.8, text/xml; q=0.7 Available: application/xrds+xml, text/html Expected: application/xrds+xml; q=1.0, text/html; q=0.8 # See http://www.rfc-editor.org/rfc/rfc3023.txt, section A.13 Accept: application/xrds Available: application/xrds+xml Expected: Accept: application/xrds+xml Available: application/xrds Expected: Accept: application/xml Available: application/xrds+xml Expected: Available: application/xrds+xml Accept: application/xml Expected: Available: Accept: not_a_content_type Expected: Available: text/html Accept: not_a_content_type, text/html Expected: text/html; q=1.0 ################################################# # The tests below this line are documentation of how this library # works. If the implementation changes, it's acceptable to change the # test to reflect that. These are specified so that we can make sure # that the current implementation actually works the way that we # expect it to given these inputs. Accept: text/html;level=1 Available: text/html Expected: text/html; q=1.0 Accept: text/html; level=1, text/html; level=9; q=0.1 Available: text/html Expected: text/html; q=1.0 Accept: text/html; level=9; q=0.1, text/html; level=1 Available: text/html Expected: text/html; q=1.0 ruby-openid-2.7.0debian.orig/test/data/test_discover/0000755000175000017500000000000012512544714022061 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/test/data/test_discover/openid_and_yadis.html0000644000175000017500000000071112512544714026237 0ustar sbadiasbadia Identity Page for Smoker

foo

ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_idp_delegate.xml0000644000175000017500000000064012512544714026402 0ustar sbadiasbadia http://specs.openid.net/auth/2.0/server http://www.myopenid.com/server http://smoker.myopenid.com/ ruby-openid-2.7.0debian.orig/test/data/test_discover/openid_1_and_2.html0000644000175000017500000000063112512544714025510 0ustar sbadiasbadia Identity Page for Smoker

foo

ruby-openid-2.7.0debian.orig/test/data/test_discover/openid_no_delegate.html0000644000175000017500000000046112512544714026554 0ustar sbadiasbadia Identity Page for Smoker

foo

ruby-openid-2.7.0debian.orig/test/data/test_discover/openid2_xrds_no_local_id.xml0000644000175000017500000000046312512544714027530 0ustar sbadiasbadia http://specs.openid.net/auth/2.0/signon http://www.myopenid.com/server ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_0entries.xml0000644000175000017500000000051612512544714025527 0ustar sbadiasbadia http://is-not-openid.unittest/ http://noffing.unittest./ ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_2entries_idp.xml0000644000175000017500000000117112512544714026363 0ustar sbadiasbadia =!1000 http://specs.openid.net/auth/2.0/signon http://www.myopenid.com/server http://smoker.myopenid.com/ http://specs.openid.net/auth/2.0/server http://www.livejournal.com/openid/server.bml ruby-openid-2.7.0debian.orig/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml0000644000175000017500000000111112512544714031036 0ustar sbadiasbadia http://specs.openid.net/auth/2.0/signon http://openid.net/signon/1.0 http://openid.net/signon/1.1 http://www.myopenid.com/server http://smoker.myopenid.com/ http://localid.mismatch.invalid/ ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_idp.xml0000644000175000017500000000055112512544714024551 0ustar sbadiasbadia http://specs.openid.net/auth/2.0/server http://www.myopenid.com/server ruby-openid-2.7.0debian.orig/test/data/test_discover/openid2_xrds.xml0000644000175000017500000000055012512544714025203 0ustar sbadiasbadia http://specs.openid.net/auth/2.0/signon http://www.myopenid.com/server http://smoker.myopenid.com/ ruby-openid-2.7.0debian.orig/test/data/test_discover/malformed_meta_tag.html0000644000175000017500000000064712512544714026565 0ustar sbadiasbadia <link rel="openid.server" href="http://www.myopenid.com/server" /> <link rel="openid.delegate" href="http://user.myopenid.com/" /> <link rel="openid2.local_id" href="http://user.myopenid.com/" /> <link rel="openid2.provider" href="http://www.myopenid.com/server" /> <meta http-equiv="X-XRDS-Location" http://www.myopenid.com/xrds?username=user.myopenid.com" /> </head> <body> </body> </html> �����������������������������������������������������������������������������������������ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_2entries_delegate.xml��������������������0000644�0001750�0001750�00000001254�12512544714�027363� 0����������������������������������������������������������������������������������������������������ustar �sbadia��������������������������sbadia�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" xmlns:openid="http://openid.net/xmlns/1.0" > <XRD> <CanonicalID>=!1000</CanonicalID> <Service priority="10"> <Type>http://openid.net/signon/1.0</Type> <URI>http://www.myopenid.com/server</URI> <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate> </Service> <Service priority="20"> <Type>http://openid.net/signon/1.0</Type> <URI>http://www.livejournal.com/openid/server.bml</URI> <openid:Delegate>http://frank.livejournal.com/</openid:Delegate> </Service> </XRD> </xrds:XRDS> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_no_delegate.xml��������������������������0000644�0001750�0001750�00000000450�12512544714�026241� 0����������������������������������������������������������������������������������������������������ustar �sbadia��������������������������sbadia�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" > <XRD> <Service priority="10"> <Type>http://openid.net/signon/1.0</Type> <URI>http://www.myopenid.com/server</URI> </Service> </XRD> </xrds:XRDS> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ruby-openid-2.7.0debian.orig/test/data/test_discover/openid_1_and_2_xrds.xml������������������������0000644�0001750�0001750�00000001024�12512544714�026401� 0����������������������������������������������������������������������������������������������������ustar �sbadia��������������������������sbadia�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" xmlns:openid="http://openid.net/xmlns/1.0" > <XRD> <Service priority="10"> <Type>http://specs.openid.net/auth/2.0/signon</Type> <Type>http://openid.net/signon/1.1</Type> <URI>http://www.myopenid.com/server</URI> <LocalID>http://smoker.myopenid.com/</LocalID> <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate> </Service> </XRD> </xrds:XRDS> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_2_bad_local_id.xml�����������������������0000644�0001750�0001750�00000000731�12512544714�026572� 0����������������������������������������������������������������������������������������������������ustar �sbadia��������������������������sbadia�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" xmlns:openid="http://openid.net/xmlns/1.0" > <XRD> <Service priority="10"> <Type>http://specs.openid.net/auth/2.0/signon</Type> <URI>http://www.myopenid.com/server</URI> <LocalID>http://smoker.myopenid.com/</LocalID> <LocalID>http://localid.mismatch.invalid/</LocalID> </Service> </XRD> </xrds:XRDS> ���������������������������������������ruby-openid-2.7.0debian.orig/test/data/test_discover/openid_utf8.html�������������������������������0000644�0001750�0001750�00000000603�12512544714�025172� 0����������������������������������������������������������������������������������������������������ustar �sbadia��������������������������sbadia�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Identity Page for Smoker

こんにちは

ruby-openid-2.7.0debian.orig/test/data/test_discover/openid.html0000644000175000017500000000056712512544714024235 0ustar sbadiasbadia Identity Page for Smoker

foo

ruby-openid-2.7.0debian.orig/test/data/test_discover/yadis_another_delegate.xml0000644000175000017500000000064212512544714027270 0ustar sbadiasbadia http://openid.net/signon/1.0 http://vroom.unittest/server http://smoker.myopenid.com/ ruby-openid-2.7.0debian.orig/test/data/test_discover/openid2.html0000644000175000017500000000057312512544714024314 0ustar sbadiasbadia Identity Page for Smoker

foo

ruby-openid-2.7.0debian.orig/test/data/n2b640000644000175000017500000021171412512544714017770 0ustar sbadiasbadiaAA== 0 AQ== 1 Ag== 2 Aw== 3 BA== 4 BQ== 5 Bg== 6 Bw== 7 CA== 8 CQ== 9 Cg== 10 Cw== 11 DA== 12 DQ== 13 Dg== 14 Dw== 15 EA== 16 EQ== 17 Eg== 18 Ew== 19 FA== 20 FQ== 21 Fg== 22 Fw== 23 GA== 24 GQ== 25 Gg== 26 Gw== 27 HA== 28 HQ== 29 Hg== 30 Hw== 31 IA== 32 IQ== 33 Ig== 34 Iw== 35 JA== 36 JQ== 37 Jg== 38 Jw== 39 KA== 40 KQ== 41 Kg== 42 Kw== 43 LA== 44 LQ== 45 Lg== 46 Lw== 47 MA== 48 MQ== 49 Mg== 50 Mw== 51 NA== 52 NQ== 53 Ng== 54 Nw== 55 OA== 56 OQ== 57 Og== 58 Ow== 59 PA== 60 PQ== 61 Pg== 62 Pw== 63 QA== 64 QQ== 65 Qg== 66 Qw== 67 RA== 68 RQ== 69 Rg== 70 Rw== 71 SA== 72 SQ== 73 Sg== 74 Sw== 75 TA== 76 TQ== 77 Tg== 78 Tw== 79 UA== 80 UQ== 81 Ug== 82 Uw== 83 VA== 84 VQ== 85 Vg== 86 Vw== 87 WA== 88 WQ== 89 Wg== 90 Ww== 91 XA== 92 XQ== 93 Xg== 94 Xw== 95 YA== 96 YQ== 97 Yg== 98 Yw== 99 ZA== 100 ZQ== 101 Zg== 102 Zw== 103 aA== 104 aQ== 105 ag== 106 aw== 107 bA== 108 bQ== 109 bg== 110 bw== 111 cA== 112 cQ== 113 cg== 114 cw== 115 dA== 116 dQ== 117 dg== 118 dw== 119 eA== 120 eQ== 121 eg== 122 ew== 123 fA== 124 fQ== 125 fg== 126 fw== 127 AIA= 128 AIE= 129 AII= 130 AIM= 131 AIQ= 132 AIU= 133 AIY= 134 AIc= 135 AIg= 136 AIk= 137 AIo= 138 AIs= 139 AIw= 140 AI0= 141 AI4= 142 AI8= 143 AJA= 144 AJE= 145 AJI= 146 AJM= 147 AJQ= 148 AJU= 149 AJY= 150 AJc= 151 AJg= 152 AJk= 153 AJo= 154 AJs= 155 AJw= 156 AJ0= 157 AJ4= 158 AJ8= 159 AKA= 160 AKE= 161 AKI= 162 AKM= 163 AKQ= 164 AKU= 165 AKY= 166 AKc= 167 AKg= 168 AKk= 169 AKo= 170 AKs= 171 AKw= 172 AK0= 173 AK4= 174 AK8= 175 ALA= 176 ALE= 177 ALI= 178 ALM= 179 ALQ= 180 ALU= 181 ALY= 182 ALc= 183 ALg= 184 ALk= 185 ALo= 186 ALs= 187 ALw= 188 AL0= 189 AL4= 190 AL8= 191 AMA= 192 AME= 193 AMI= 194 AMM= 195 AMQ= 196 AMU= 197 AMY= 198 AMc= 199 AMg= 200 AMk= 201 AMo= 202 AMs= 203 AMw= 204 AM0= 205 AM4= 206 AM8= 207 ANA= 208 ANE= 209 ANI= 210 ANM= 211 ANQ= 212 ANU= 213 ANY= 214 ANc= 215 ANg= 216 ANk= 217 ANo= 218 ANs= 219 ANw= 220 AN0= 221 AN4= 222 AN8= 223 AOA= 224 AOE= 225 AOI= 226 AOM= 227 AOQ= 228 AOU= 229 AOY= 230 AOc= 231 AOg= 232 AOk= 233 AOo= 234 AOs= 235 AOw= 236 AO0= 237 AO4= 238 AO8= 239 APA= 240 APE= 241 API= 242 APM= 243 APQ= 244 APU= 245 APY= 246 APc= 247 APg= 248 APk= 249 APo= 250 APs= 251 APw= 252 AP0= 253 AP4= 254 AP8= 255 AQA= 256 AQE= 257 AQI= 258 AQM= 259 AQQ= 260 AQU= 261 AQY= 262 AQc= 263 AQg= 264 AQk= 265 AQo= 266 AQs= 267 AQw= 268 AQ0= 269 AQ4= 270 AQ8= 271 ARA= 272 ARE= 273 ARI= 274 ARM= 275 ARQ= 276 ARU= 277 ARY= 278 ARc= 279 ARg= 280 ARk= 281 ARo= 282 ARs= 283 ARw= 284 AR0= 285 AR4= 286 AR8= 287 ASA= 288 ASE= 289 ASI= 290 ASM= 291 ASQ= 292 ASU= 293 ASY= 294 ASc= 295 ASg= 296 ASk= 297 ASo= 298 ASs= 299 ASw= 300 AS0= 301 AS4= 302 AS8= 303 ATA= 304 ATE= 305 ATI= 306 ATM= 307 ATQ= 308 ATU= 309 ATY= 310 ATc= 311 ATg= 312 ATk= 313 ATo= 314 ATs= 315 ATw= 316 AT0= 317 AT4= 318 AT8= 319 AUA= 320 AUE= 321 AUI= 322 AUM= 323 AUQ= 324 AUU= 325 AUY= 326 AUc= 327 AUg= 328 AUk= 329 AUo= 330 AUs= 331 AUw= 332 AU0= 333 AU4= 334 AU8= 335 AVA= 336 AVE= 337 AVI= 338 AVM= 339 AVQ= 340 AVU= 341 AVY= 342 AVc= 343 AVg= 344 AVk= 345 AVo= 346 AVs= 347 AVw= 348 AV0= 349 AV4= 350 AV8= 351 AWA= 352 AWE= 353 AWI= 354 AWM= 355 AWQ= 356 AWU= 357 AWY= 358 AWc= 359 AWg= 360 AWk= 361 AWo= 362 AWs= 363 AWw= 364 AW0= 365 AW4= 366 AW8= 367 AXA= 368 AXE= 369 AXI= 370 AXM= 371 AXQ= 372 AXU= 373 AXY= 374 AXc= 375 AXg= 376 AXk= 377 AXo= 378 AXs= 379 AXw= 380 AX0= 381 AX4= 382 AX8= 383 AYA= 384 AYE= 385 AYI= 386 AYM= 387 AYQ= 388 AYU= 389 AYY= 390 AYc= 391 AYg= 392 AYk= 393 AYo= 394 AYs= 395 AYw= 396 AY0= 397 AY4= 398 AY8= 399 AZA= 400 AZE= 401 AZI= 402 AZM= 403 AZQ= 404 AZU= 405 AZY= 406 AZc= 407 AZg= 408 AZk= 409 AZo= 410 AZs= 411 AZw= 412 AZ0= 413 AZ4= 414 AZ8= 415 AaA= 416 AaE= 417 AaI= 418 AaM= 419 AaQ= 420 AaU= 421 AaY= 422 Aac= 423 Aag= 424 Aak= 425 Aao= 426 Aas= 427 Aaw= 428 Aa0= 429 Aa4= 430 Aa8= 431 AbA= 432 AbE= 433 AbI= 434 AbM= 435 AbQ= 436 AbU= 437 AbY= 438 Abc= 439 Abg= 440 Abk= 441 Abo= 442 Abs= 443 Abw= 444 Ab0= 445 Ab4= 446 Ab8= 447 AcA= 448 AcE= 449 AcI= 450 AcM= 451 AcQ= 452 AcU= 453 AcY= 454 Acc= 455 Acg= 456 Ack= 457 Aco= 458 Acs= 459 Acw= 460 Ac0= 461 Ac4= 462 Ac8= 463 AdA= 464 AdE= 465 AdI= 466 AdM= 467 AdQ= 468 AdU= 469 AdY= 470 Adc= 471 Adg= 472 Adk= 473 Ado= 474 Ads= 475 Adw= 476 Ad0= 477 Ad4= 478 Ad8= 479 AeA= 480 AeE= 481 AeI= 482 AeM= 483 AeQ= 484 AeU= 485 AeY= 486 Aec= 487 Aeg= 488 Aek= 489 Aeo= 490 Aes= 491 Aew= 492 Ae0= 493 Ae4= 494 Ae8= 495 AfA= 496 AfE= 497 AfI= 498 AfM= 499 AfQ= 500 AfU= 501 AfY= 502 Afc= 503 Afg= 504 Afk= 505 Afo= 506 Afs= 507 Afw= 508 Af0= 509 Af4= 510 Af8= 511 AgA= 512 ALDs7paJl5xPh6ORH61iDA6pONpV0rTjGiTkLEW2JsVsRKaRiS4AGn2PTR1UZXP0vXAmRXwdSegQgWPUp3Hm3RofRcDh1SykZBLif7ulau1hVO+rhwRyKc7F8F+7LcMf/v+s73eOXUDbbI2r52wfr7skZy/IELhsC8EK6HzhACI3 124241322153253947064453752054205174382289463089695815605736438952932114700118408072544073767229325045596832952652232288773280299665950768731398747700657715829631597019676014848183966683866396215048196276450953653433516126074463193382764063985175903718735372053536664711482497859539116009770850968340298474039 AOzgU1s6Pd2IkrJlvGND8legXTe50nyDCocI5mwT9rW0YsisY5jaaEOcu51BAq9MmXBPeVX0k/jlXwH4Pn3mCpUAU1rEOsTdcmSJp35siKliDdhTZHHdZNMW+igfXGX5OCsA/BaBcGnE6NnrGWXKyTOoVUGQLEkL2T5yhNUaCT83 166340174936369324883416612727439279977041963320514134445183426741643586944819834936989524033374309932122967866930503619179389342537723598234062828695747850043368572301869699886931403612266216965783079972698791813140295203826980649434652168563255385527187360027803388963151668338040517316899628026707657178935 AO8hrpw+lDiJ13JahLtCb1RenupQcNd0wlTSck9OLL8wB/x6gAoj0PTLV05eZIbz43N3GUSDmmckjlxdHXiBJ9rsoB0P95l1CWIV+4rXblCqxmOdmlm6VZ13bqbI0x7l0cjeMrkmk+yJ067WqUolqQBlUWMTuJVfkxALJYH5xr/C 167923899524385316022824282304301434707626789716026029252173742527362300338760906999615029022863637963070711762128687835779073122264515776657475985362344360699359591353388569856862973447791264902182048648600267737826849280828116753682917256540180401899752566540869918949003470368970029744573140084219550547906 QxAn7yrdVs5tlHV+Glbqdaj67c6Ni8am3bBLOL8PV5HbdrLf2xIPmNugo6MfUwFSnT+ZPJ51+VTOsItaNwCFju0Eh1cqyP3JWyLRPE7emKuo6xRhf+5ik0pTg77LEF4JXW6ofDqirpR4alFi0G2d9yImQPphsYJwYGF/nNT8u0Q= 47093316905427544098193936500644355852669366083115552072584429220248776817916430034648347490325490701471113667554329499736495877969341478442613611948220957798780043076906836236556612316544460763366275536846463456405604189392790111985912854476264292503164100482712281088955640964034295834935468665872932715332 AI9PVzrbJUvmCihwSFans1lBKwudGEZpWWu8pkSK2zVgzGhMvUoGgMp6TG2zsUd1tV8zv7KsVD2t6pXmjT1wPUynufq97GVHI06SGpflDTt30WboYRh3DgYxvso1sOjUXpnDezcaqc2Aiz4nV5MSShkBlyBjA8z2worHDE+uXqw0 100635651531872121827765663065728398779771663753008344681972226973080394359405041113312675686974926993279775427390065833081040771269307007695807025882757371805607979134114890454059957194316765342461291139168706134406917264848659448693866813989352429841300235734400772946895458374870482441457514575059390213172 FiinVicXOqqRLpxcGTorQpSAGeQ/PfDOuzYK9ViFtmPv6D0cYPfhUH4qXEHOejvmX+0b4lfaX8MWPVZxlqpfXiU9BhG76HJxkLF4ysipukeOvhoHzvcxE5bnhSF1i//bOSifATBLBEZInwqSVg5tHHPuuCkwTL91NqhOulp7Lsk= 15560440884463435471963622630292643727112462888414585143143739400703889930416938984547754943252935620248108237258540176511252143752416771350868493435174026287082706690332705481726295797196444796135827460509780634261726494455068460028424141500629527968240913757449787164107068039175831847071025316475940056777 aYrxyQN/hkBne2ayqo2/iDLF3DZGgk080SOMJfsj9h3Z1OfFZM7TJA+y+/O7niqatosvKrfHrAw+Qs7c6tCZ6NPwYJ4QJLOF9bqH2u2a3fkI954voNUctlUagYUJsZXV8hdhLM6NwUyIZ3ZFkPcpTZp7nKQQ84tr1a8VjDIT5/o= 74114640794666001532816944350975062126079079113921109750255283189037502412929005615388097912507598112836936032143435813588205939470002911374442844578739574773399427907766548612582213272643279263782396527705126350063372192910060171635870872236876399794128383338399728947176692692942605589343038282957050865658 AMpCUeKUX/vtRslWiUUuXNl1KA9uDAWjMUkTrdsxxRDESI7iZIn3TR9lW+0kV5fzkLF18iYLAwSGBmX1PS/T0UVFmoBPJ9yS7yktNL0lpQ3noyGFn8HHZ6XB3FkH3jegIfGbvwwhnhhFzpHPrXlpO5iU5Y+rexzp2XHWt4yJGuIL 142031143422642739313498629438991149460874309300342349421794421544918823888598660275343727563280565210534243383322796489809683834300630555650331646026843796764549231159336347965502383849513994449309613369541991287590422095953275586374371960367000083487965487661436037637475372929033613295072397262739084075531 AIMIQVz0JIEKEI+PREu94m3v9XoiU/Q0CpsSuqkwSSje+Wyul5ea9oU5qgtOpdkMUOW91BJo0DW/GMZ8v3C4qyyP29TtjCcAHObJi9hfLSlnTSuzXZnDStooYYKqzfToLToCaAJKCXiXAVW0vWtapLnyqafrf/KgyGZ5u4HfXKY0 92013973253053602863003242446596060337454881568126916916519869242232429836082762281129448384605359749247852792606718908482332975424967542242332487707042773885428473061056052851768940900752317020681189773407893371297668591494665352294885305475871917069040377145530889271334616499701769138948975263435137525300 ANfP+zPBTR27afneyac1KJhOB5Pq3AXB+SoAXJvQI/GkSoNhw5KdfqoIkLcoJi8wClCm424Gm1AdrdGwDFOM/iKTSPkrvMag93+b2EbQGX66/n2X3YRFNkgq/Gtb+2M8oCcAL054Z/iiMD67aU5RWzjqS64ePHsn01bJ7dqLgpMO 151548639867177154896951257541227014781655576169318283047778755573323724856619156348444192550664853912434681577093459933599575436686424046466113215132845213008587152894642577278656978304699131916299275797578171518984206145555369576872231567191579337901913492071976578289189524123204040497290426960375042970382 AK0kHtacLGu1NFWMADq2rG8hpzM4UEYyPOL+aMJbnwXcUYptRIxb0YFZg35RN/RiZs4lQsiq+kEJKzMMV71TsJq59vMkIZhZoB3t8g9ZqBZuq0JYcTICDwRpNSttJidVpJ6P9sR3s1xPMYKdlSwt6EEc9htOXfZU+yHKYgn98X60 121583812047864398969816595368193171848971298823388059338224714026742264861090347096116404814514279627148994345584790617974476594451626305761040465570524035369799925437276511604752129817947910677564301623631349399504187314174538914591944778074509068973226322566160587813128746039859381466427380402262866230964 W3sZlWW1Aev3x/DiH9MzwCAZzBj++x9cknLfGAHwgFqkLH6vimEH/r8hi85hzlCOG5CjwhoZ0D/Hsfr26ZJ3X4chG84byrfDnek1V9mm1++v+clJvlYgcuVgn2Opsba2TILTm1MDB+Ujs9brJ2AAKrE9+ep5nvtQVeG9PUGtdlo= 64240043913835461386212515483198059541440539167395859777194837833769712010594411295323900074066077107346806786205590345517755715510695858065925747020336398305793661773798243627926904542715123849691490667964262778804487343218972081260210371192903128886030021862362141928329650003493687310970684093289133340250 FTQRk9/BIj21gbLwI22fHJWYj+8Ghdcc613hOtJ+/hQmh73HwTXLpaGK9aCptxVbpjW0r/bxaRjmgxu9u1CCZh5yRd7Z46Wk/LIPXGd3ycQzqRMFB7TISFQGJIcFoxRp3Eb5wa2OyrUg7c/D+kb7oFJq9P7mEwIh8TpLzwmu4SU= 14889529068556301710329043521845510156960298822469914567758538023025100741826628180855835334285179977296740667353391766487166458692144569279381035582718738461626140662441222061900764829681913534146898551570916312642104487829660946024590782808750587095559047648957238487820069966851521487428624726655438348581 APYXO6uGvs9qWiEAkcWsaCaCrGJJCP2Z1g++XlJ67oZIgEoWITn3T/R2/c4edAfwUUzNHAYZN1h2dSrRoqlrRXrbxFtGOuRCUrXcGLFFcEbTrtm+z5z8xGRfcorx7Cu3FIBPMK5XcGPcbRZdyP1gBkeDMvuBNAo0/To+LP/dhCNM 172810804474418448604443090732221483571611665465870520701624598983692130272337358406272727413570938793741430131635927237320173996217984860203754686741782921346604605228620148450611724714868551781003004492587584071978757421616871762681049508123223983431502852926521520561941051298696758046005573332373854233420 AIDNxhnDEe1kTJ3XGfTS8zKXeXPRdw5yifm8j8Ibzj/quExy7hFPtKct8hRskPR2qwTlMiW9Ra8Npg2USsqHV0rBoIkX7E3psxq5LBfp/q00l3SEBuLL4K2FGR87bPgU+Duk3RVrNMnColiTcnAR5XkoeWhn/r9MfJMIN9Y0FEh8 90449107125498302548188660544012777357148118984122992664008792590422284061463729084479315745509706793674355738023180454297730948397413371686013210006834869294564190666543874617716180411178090109573192518129248278410216362657350215009192850017507998797754539132540293137589672869131300859207213449571846080636 AIRWavxYRsGlH0Yr0DudwrpYtbrByf9ZsDawKom7ubiRfepqYzcBlwt4adMMnkYSaXeYtOsD4KBm2ZvLKN3++RkYNmxgkyarORBEg7ERyiThBj7Ksw57pNHCAoHtBEhH7Wp9mHhuZtPvPgCEptmwCu9rYhLt4zZp+Zq8a02dkXvM 92930601962515884925250459851491509622611227724602941760145671636277317511265759558869239180653492283311584982044597979173761619470326096725838197524704577188104121460089235709339932110663536557497112887112782062772810759971739760085128369628777812332518137107605855679096146402427144185104230596200130247628 AMNJGLcAiJtL5fUfkesWKYJurdYSnvsOZeZcrg7bemkEVjF6S9CcojimUl+ncr/YY5/EXnU0mg84fObtDxWWdJ7z7l0CFcoALTyEatDYKshT0xvdKY3u+LUShxIAyk8EcGnf+KoEaa4Mx3tg2oTBnVegXClOakNTWw8bu2ItagoQ 137134165107366719462230252606689766470445826753581409513106273517221906418464863733870948759313279128624638614534848890858250894834883265387344539280755177217350585564186248554307335197387734431939154077778003706720017441895613190141376534460438929588407764609772857975000507660651583780079804513519571438096 BmGPZt8XqqI1PuLN4K1/PZMi2rfOYtHEMrcwZdSjKRm5qTkd0Pbb/5zPV07TnM0uLRvIQYTLloEY+GYyn0K5gDTEZpEtQ8ee6Y87zYGDwcf20eqYNxkA7FVV71vqCP/Uw3Oi6B+hMvsWZbvv2vH6MkAeADCrezOtwqVS+irftyc= 4480956865245875120472829476982311611308898564405318773810939350829150182630548948231116574193987272498161864310429976564278532538229396846813874244969927890037756969704618336242255039858182439641759659872128285423988638335967412040624105824571426792562334458751137508116412821914961236269913776304372561703 APqFgCIYbJWuRyEGuOStPvcprj2PILQ0JpgwQ2jLKn3DvkWSd83qh7PWGKozGavsjh803K+ZzI7P2wP+Nc0r0El3q4nzaHvKaCtVRyMwbXv9wYLFZICeM6J1l9ljUMts4tbDoPzkIy3ScU7pYxarBWqMkcBU8qL6NN1vEdkeu0fW 175922170410080716883576123079908758276229469783745771772401183721225804343343063277676406040455068452258961299511343441961963941297631097736305638850193978800615558067791016294285848963023036905095022181004058235239390870177623185946205281141386416867569004073524130001309977475780893497185890756991672600534 APA/rCcGeH6A+6ZwaBBDM6mB6tTD8mjkrOWEo/pK3MCZ+rrErMBnFp2S19GhlLOfuY8BHS+D834Fdm8+3wKYkWnXZpGb+e3v8ofOQ34G1HvzULOYtrEiC4ISZRt2SSyz2hU+PBXjVnplsHWTRxZDmBxTJdgli4ItAqxGCxj/aJ9m 168708388929747822981923386197903561880341990893945097067702518857172133291360611402092714329372304718329568897960770488377524912057166920574319430820488930520807742026377043178502591886293565177404635365772829346030773275726024973460121300339258054215286249329967181244588558220467488638468686270735376228198 AKmwrLP108dCGWOWxE/6woJVLRi/Kra/DvdsPkkrZQmWIlUT7IvwM4gU6bUr4f6wpT08cIQls2cGh7dbSEaO0xLa3mmtKhPiAlzSnz0wuifF3JT9U3uXgUfCZuFtE0z7Oi7WTOrpl3k3GA7JFvXnY0lwblIQALVf6oWyNETnajGl 119160465301384937485959146028591622947513292915838943629387700439301197965652871741710280647524383590817798553034250156068573474278225305190573334054718387045488098320076877626430189054572361967283632592181431701411266656256255758079114072932140551282607247364388070762970060420036793573956057551235306893733 VTe3rCzAL1Sljo3QAXEkAdBy1ZARHZwtrj6ZNRa5ttqd6/l21g4z3iHCeGo4rnE2F8wYTy+NlugjXw86OS+XojW5y6UzTtx0HX5IJ4POqN64aXWmaklGzroBEYWeuFFKcgQN3NOxkuJoDQ6VElP7Epz69kj5CsKJUwL0SjbNrFY= 59841866347633473702601462509811342285929528424012250265905695635971518533504187799047710303717472950129869674786231155102509311322791323986824635569605105662070745033595366004805920086888891275288347907772640070278731650628917037915863439204501060041944275512863990729926528905725569467329169134226609384534 AIZt1xGhC/HrvpPASsvVIVdsu//tn0noyJmVYh3FdQ6yIh1uce47iCsrV1yvYqx5ZTbC0vnfnbjFcWqH+HtLX/DelgvhEwzqJ8hwQrfE1ShLG4ZjAVo1Z4GCjrDcEUMlwKcunuSJssuxeQuXwTLS92+q6QeBSS7OmfxPX29CLb4B 94399298271083745508290936113986978382457275531684761701599029877008571741877683365769553170771833981099580359640421358853566501815723434822307977440496208486103754978934472597505865596938563438311337045817621762649604204720249750058676095769230214181772215323235427976398686727606000594646472236822594174465 NIhTPpWXS82VTA0LTd6TfM+HgLgUcmvnMYtLqPpuqCKZwalAycwl0XFYNyVvaY21J94j92ts/lRYgVtHDhk7/9nLXq5js/lsUnG8rWPHJo11JTxvW+df88aX0pw8u+biOWt87vc1MW1dsMTTsJFJAeBx77qU/Cwto95IVqM7vSE= 36889590210230649939994518345793530042252563793069578097360569338647730438860274349862767107939590441616825589851005429465345268710487649366046960918184701290985280638488938340668212498212581853679035928093386035688597446809895381618260692378376844452061580510108168030682664507293277674052032318576713776417 KXdi4A2Z7tSiiX9YGtDtxUXIfQvPhcc48rUH+Q2SnXL7fLNmr+F4Rf3RiFBRiHKocPfE94pothop5qQJ5X221/DbEKWK6s+ChfQ636jvRxojoLMab3dPtaAPpDJHrfZMxbT4ZaDJT0tpA2e+zZrzBuDs+UUgCpty9nxtdm1gS7A= 29118662951481660380477444121362422614202367719725087486810943918529894738076273660245405874301505615796632229852040910511025841576465052938308369421493312085081188509808322692130449282585522349552501983296872614029139293444558468751646868108213623606366977549477663987815308260383403466635254115908032940976 AIOTBZQR2EJJRmoWdRNFLG4fceoS3KnRTHRpPdllhHODqdg+QxTOcOvqIzBqgdD0JgO12SuNAjLQOiz0jhd02qkXw9Y1adGuKvL97ARFtNEuJiNzFAj7KpDLy2zk2rPJp4Lp7cjQs0fe8BQYnTzTsNRGm+4ybln/gse1YWu9w8y5 92394618277596007469808288231093678404089765494062813665106014405059399079199990128824492247005602685377185496959522609467906358619318009231448503013528692450191782140091818984176967246749464502089280153086163239846744554575017530385347720563798041108608545014076448155956762636929707905789978331102411214009 NzfbJRBF4pqEeborJrjoknJgpfK+DZh2k9cE5dcElMPZ2Zn9im7desWGiBSQnu3KbTO4L/t4+m6nFTNcbIJnqbVSMDHdsfG72rG/t89aOuECQw0HMVVgONNNa6i/mw0jZSWnRLD4fa1YgbUlMd8jeqO9XcBDB4mVtDTxyeGa3vU= 38775530011374537813502898274019389132620116890266344603221997943675706375698597061571989090674289834838060050848545748579361837989319487970580969082824601965845786771062335733318139530316825802589479118956745739691326447349403950997231306042638797277408335778415717988679050762936401945487285814799382535925 Y4BVPZ6necuLSwaqYEPeZp0lt9tTGFl/WCJJbwg7XpyvuwYKtzagC1NLzY5ymBfwGFw1yRlQuyGsYd9mBfC99DuVCIeh0JNrhJN1bNfoSzy5UO5+dmTr+dm66VGSRS0tFcViDTfCIleTV+zxo/xuZT+Bjxq7kZue8zGkjp42Kmo= 69872189501616471647606976308259279995249122669120675885925763529037695584466011511740991152346215507625265226811128801733353566555339153627478941716586678793853828514394269931890370517258825006937741437480128878717892485074131232336852490940507703859793477547154689914725314529986438108117871674332626168426 AKCP9Mto4q/a2xNqM4N7PekbKspwt48OGPre+iqVwPrSP/jWKxg3CvvLNZzN5P+/FiUGIklMMFJ8w76OaHIPqKuwckj1gvCLECJEE+UAZWrNKPmpzd/ootN9/kQhNMuloTFCyhXAUUOXJ7Z0WVLb2u6fn4zroszSMBoWQEKC6lcq 112750701794692134675959811050012620191158543234019977304167102486465198271340022889272244811582365901584420008564301920174477182946432553537794834985703732129975734658113610563794129371053853971031300761815004524681756388784922001759202643614966614186697992611399618828963452661554240362943588548146868410154 APOTAFA2waoAODECaGNgCHa8dNN+cjMnD01M+IeQFytzo9RLMzzzg/gpTUFpyLtFMcfbCkDYQMLXwE4crTimdz5sVvjGQ+5fSFQjoDY6Bw7MO6NAcLzlV/sI/1WyNBKaLQbcl2720n16tdUcdckQNnV+cC2J48CVxYM1c7QQlxA0 171043636512232272455501595416608280460445723238023572475354665686544174728784633443479486247342724860289312593374524429736857970220153680852977711594899595712511352458264354251161579203922747468321999465061463474727943140910084880926005209538535217464825087114791420210981711903880998556269523363208766099508 AMGpxRlB8WVnsGqyyiy3/mzrPymtJW1o1HcDErK11ZwQV5PwTF3c0THwlnxDmcziLWHSWgPQwfRddVDCXMGW9BffJn+XO6aTcWDPmDAh+1DbWJPE1aqApGbHvQ8HONy90dQMZf1ayuwceWCVTuU1wnHdo9F/sIsRbuu7ic2OJDzY 135994898408425255747055209966103741651849229328236418804928584233229830656742052333413774490626915784901255640138520158698845938184666683995579777154437927013722740366497459963753542029774185193376253885864514386760437194444013834088425088260658670140534670789371556026135595577395047002643901630053097946328 AJAw4uDYdSYkOrjtwJVWLv3pi1+UxWge4RmkWKqVquTsAVcT2tRZ+MFdHM457Hl7fmFIyxvGZQy4c2v1AbHEfPR8ID2sCRQpdcfrxEUZPMDqxfnHHm0ziny6W4X6ggdBzMp/sBWaVNTBL0e61/pELBGYNRGFMzGws7HQkr/sro1D 101254336834199527040756567675327011562230719161388328289463594628690618298993695452746353237675715087353241661592074446889034411683413957950360025295995263477031608845241728493807755308798509893719674568267846671753070163272328014412744008880395248474446310603301447848026040555910147467745595720879397834051 AM09TdtXgYL4FI5CGNiVjf0T/AN/pZ5zZsBOi1MAUKMURiXnc1x8VKYTqM9Xb86mqNBBqphynIQG6/3e/YbGJgHlsSdrmKbo+P9daMr02I/7Z76/7Osa8+7Ky6lhVCbU3F0tBH4WvopkCQmuJ267afgvDD5kB+9uNr28deMH00cY 144124056591600568767398029380314564902309327093641173350205276895603332085753288682409279238417493662029954512382520307259348748813767324609446500382301421328754981718014234615523158887865271179104711373675849713359713282937065993613915015084108700238420759344034475478243507306107546245540340758766909867800 AKDhK+/BKGXbrbBh2vM61OP8LN81YwlJKe68KNwUu4tjXlQg7i49Jis7QKPI/YFPUpSNTu5N2iCgeMnCX4+r3NAfivOao9lw4N3nc9bi839SIWdlokhwBHBYmCIgjehUeBAdkU4jKqlE06pIrpRmSvBtn7O4aWTbT+C++ViYAcGF 112973480670453665543892521898882856059335781900313607790238402438320486344365203510769919022496690291280873287383392088872774202832124927485754495093552572232234532821756395965072330282810574669371524103814871172318519695921477775100282448247625395376072233777533359104085023946019406729587713120941266551173 ALxDiSxHjfxvP8ETvpE+SyDPTS7q3o3zCK519WTepygC58KSRfvDnIVIyV3toQKzgqD50kF1Ni5D/wuaSs62y3zg3kELX1g+WuBCc8+x50+kDtbHXa1Me3et/OqVS/QeppkcjK1UZMU29fXze6P/w6aQfvKQkE7koeQtZBKkYc0p 132203344567902304830160099595561253300484092355345272411265169562971473393256361094745618829297250316196312398486598077249124198329075791740755862221465178128527292695331061023291345396067863215552021206609309872689233899464919108147533679134727064586730810633196817136739658243232643507412032417747255282985 VF0YUTvy8Mfi5o6X06DEvLm87r72mAtTdyyLNr0/GXlk0Xj3L2Oi2bVUMtcXQNRXg/mkdGP88pgdaP/eMzqkUU++vJ7t3UgOC1i3SHegpiBhhZh+aZHH/wjFV8Mz2XZB5z8MpMgN+QwALK1TT2Pyt/feQTsOy0imVanB5+OvCeQ= 59242171319056188000481457618922567543461456096441095927600135114274111606802456239311634638536207588762066940095527920532936960549439269891703098017342732142860571277442598349453761561189719823290643146391349978698217357430495238876700400634593256155537598291759795109752990651995982467695091946768443574756 ezpwBt0N6QhTusiPcKrBvSB6yuk/KShTLUFQHdf5J1u1fgDYrp+aOWuXOFVfOd0bweiG4UxBQNXB2IDFWfYON0fBoaDqNk/41YyqXBSkKbiNWLi1y3zPmwTAiwK0PzYp2EPfk/t/j0HsDbvebu0ygcxb2tPqj4EQ1TXEdD007kU= 86533835313999945727720083706940213467453975054116752898416709637030456504024135513972566184073843025739226187558143854850980654667596935003124034699919861200483994576288766702308068265526535622439762454501169018136389983894783905946543636163866717367545972667876983557989192393479830223914708619684891389509 U8BT26zT46tTZnkmTNxGUAlXbJhk5cNi4AMSd8fSvZHm55siMFGJ8Jl7mtdzEFR1UFAyEztf2fUhxdtMLe8ei/OJgM0j7myQ9STucEwnsShT7QS/DjBmfvcC42sl1CRpXkb0ZLrEJCPf+crtLKGrG7ExS1oawIAgALBiMQIL6mE= 58812148564290791415180898639607206220554150794356494356250223429674091688305329629529905854147200457536549527135776329004085047145097927266797668252160196098870200925284256433894773392353678965699083286106628662506590268955650280670838340651598082083455821825076016227525614626726458235627297885815646710369 HfYii3U1SIkBZl09RHaGGA7H3np+qxyNeeCNY07PDl8LwZAaaYk/bHPeBVboan0I2X4o78zCD/gFXFBJ4rxwwUsVjHEioyO2JcpV2/oDOelJBD//78WzBMMSWt7ZKbJV9uYr9ZUM0BUD3fsk1esFCEdnDJdr86U0UMmiig2R+ME= 21039655953870571289679214995029926285040274249531458675115179004718812090027267801012507748013357317597416722235988917212676802092082137617336199787762782958420742299451435320649616271885264333948336627286638368859041172783505464468640994920853000441536629081040963398001710173320125308624362209157720438977 AICOlee3daFyqTrTdtWjVb5M2rclh9BpIo1CRvKo2bF7NYcjrU0/VvbOnTVXDwdeGMLupbi76f0BrfDxYtkzMXvIZlgoTit4g5ennnklDHFBC5cogaGlri8U28w4/h5oMunZ1O4ezdpRgVJe9nTP/sSEMYiNS5IA7Zshdvm/XccF 90275777798511290102824338787811725003177532250296755103300529948194832904403489332420505850668003332750291879153080212231952155092379375422537931240723308384652734942204313672973885652497290433943089371705605128843469306776615573873479312715317072986990219294942040272550822460408702072075001377245051602693 L0QUSVIjxvE201b1ztRZyOOxy8vkUz6626TH4tbLwXjjc+AhmrvplaVlavnOgHqve+/L18XNuAYP4BqdxIcWTx+yxBKm4ZS92dRJdcAtccvZpEJtYjdJvI6qbL5Ph6HluaVZwp4dyFyXuZOJGTfYdTb7PUWM0jNT/xsqyjxSQ2U= 33191267986826803728285073844005357792766429917696698533494382218509532051029343127452480789088572904364699220151221680328978554239767633887572649589456766209242252549993823283929686430100804479376247660556781589549613316880150951333982646510273364068770923588389668733632648346075516618646974067295703417701 APlD9ECKJuACUmQUsbd2GTOpb2PgQVT08C/5hyNEVdA5bWoICX7epmoCKCybdolk+cfEBP6fSz33j+Vn8MbeiHBLdmF6ETbmcyOjldJ902MDvU8dqAa8IgEZN5Uh5x/xzN+3dqk9o0ji7yi291u90rpfIh85PPpDat2B4l5zs9i5 175040148659257809883308984693597046378367187659749953472629929701758633206586720399909808941145946314755491399962797299295431089674294356220216615950668954164397362123668926410543898553191541662075745481299747832013627018846822876386760538344447600390187421938699064459451308870669878673306013635576901916857 KB7N0tE+A5vFhyrd/m6Qe1wTihkjqmBn+rinfmMAzRlvtxIBSyDLzQsOQs7L4oTG64ABU+YwcWVijvoeZNamaxGl4hatAH1pRqmC/r8FMvC4vqiFTbFHzQhkjM7uoHD1aKnxyBVgjMj0E0KZjrRxydZjIR2p13FXjLP3UQSFtII= 28173452509830313810392326357601136401754938805266458365469366750775669869895498658593356375710132149836430968810246171974040975430205200958564616924399794768861923079158311829444850822144940112488994119845741191519421434257276977333662656888696213514226866147767570046232093727585815615828360199830275208322 bxFgV7eXwnbQScl4VzS3RTdcMW+NY6pcGkT1UsqHIeDVyBb8DnH/2/Z+DX3zniR1iW6FPdvhJJeQyPIax1ohILa11R27C1TLxGvTrRBGUycxjEcBIxamHveBsXbECWusYLEakeSDg9x4BTWMz1rTQajkorBoeEjYuW+xBxQtXME= 77994515143740690952370766995249847650881300682406161400195705464876513409097078624084133111941171517535435606295232558665316819077765607639545069239931096306624817379462598756505457054433358548941076472902905065316335603665413114267741896000877284610377452471067725794013283338924419969559537339967562669249 AOH6E2eBzD76QdTJ6QbR/7OeF7AagUif9pEYx7fMqrIsXCJKKpLV/RHIItCDYP2WO4URCaVueoAJe3M/Shj4o6efvH9pf5Q8MLM0rn5MTHWhThivqYQDwjCp1ZsPgq1VFS+gcnmwgHhj2W7XzJxiNPeRXlxI2vL+XTT/wPBYhqEP 158686346608862569574095184731081143351413141116869402750758091813874232272198082464382169470744476593016502816563462778075467588097653320101723165887488327616477297401486647183409348122990505635004320879840358339260797834264972100385692477324858942142372580281421734058008608134075577990829273447077276721423 ANDDgNXOB/rXwmS4KEjiHj7RCDocVrMv5SU0aw6AJzNTBfseFngqidXx2AJKOEeG7RDDN2gzn4K4qJktF0AIPG2JbELlLUu0MFlpOLxamp586qyp67Cl9OuPq3UZTyQhIsSIE3VQkvxuQkGsaV1owDV3BKIWQbQEqMQI3yT4ELHm 146598844784260148346676185962272439320781765598895126402049215152385925250917998794921584290777625240122575975327405909800121511343265147922400813488099624745229653124857224399973509428158163452130086943873214460600035260925149630502192183407327427517292065083168010281295559088633086659209316582810260124134 Vprr6oBnWuxIzyTZjuxlKSdZhBc0upeNBHVIlXpQEnN1Q+XURKzp4/6Vg/koITftr3SMSgGpE7LkrERMGFgYaqM5XZ1RXYFKT9dRJnz9VRDITVZtdkDrU04bqo2Ur+jvZhvg/oHBDTgQ4nPLJfHO3+GEmUtck+g/wOVozMMgufY= 60816213163057201559480662231646403262735082707152897397414589876256824040344252799972529759737904461369360580708093117244392116003622336721789703580184437841209963565058475060017600871779929808204093448248984201640754565635410002090180110910120481044515630478472999135146756643143415057403006410330361346550 do4LGsm0afQLHl9alWF2RVyEKPxLIErsf4pTPgScRE7ZiTSVErbCDeyzd/KHzhBLQs/DhHHcw+OXj541cIRm6jaLVKiT8EwLW/dVG0AkVli83sFh2f56Kk+bCGSKvfGEQcGLY2k7nQ06zoMlYR/xbZCka6Q6kSq4YBDQgigQ1lU= 83252051731120517035090523892596419800592471447735288551342681962005778435125655090199060145942826521644585427683714084736143440310518046334877897672493531918539106001203807757254797471481884534543367685912500572052457610702790097953420236852480969038388056545966568595395722585797418296411673622376893961813 OL2Qoj4xkqRrQmuuLwrABG3BMMBNGjfBtVBNTdBf7g027Ghkk/z3aK3jKT1EPpdiOdn8zXYBSO1mTRGyK3n7Jo8ICOcnlBOF6cZtDsb9bvSVE26MOD2wzl6irU7vzS+s3vGBkN3AazrxPD4czk3xezA9y13DJVnNzgAgIQHEols= 39844525812817530522650122383059885756573694015271773938493414420875846359054562126060762455794481186614035892021706051863945033061233991184379580556219478200155757966121832613842937722944431875100059046588723473670448006803481527981834627086055642349130254917244469014754132003347635357123155857820000494171 Ljgn+3Hcg5DOf6usRumk7P+ZrdTBRmo968HdZU1mS7LwLW3Hii2KNkwMV7J77zA0P1pnvhMSEEeh1RbCUjLtSIbt3RIcOEoc+aO0eINF8r99l83xF57CBI3MDA3AAbtaYATy/NUXSC2h4W5kdsQuR88139MFi5y8E5njqxHu3UI= 32456338403763561215581247445990611953939298888251578685087656354454727113846722731945605696397627662593375001096230320486703167389461057538581895745078593206660798580358701927596287363374862536765135996838944212622199018632046955402325290145163082309469649329852148345837780541107029165352782710901375425858 AMt5/u+ZUNm+Xsucr4RQPUu6ExAOq/Jbcjm/Kb2YIAaEQ1czIL82wsu6YmpHcfMaxLjY+EnaaF+eCWQPeGd1av919+QFbQPeh5DT7ZT9klK7BFyVsN0nEDJQ3AMMJqq6lm4sUeVxDVTmMypYnkzRl7jqzyCRY1MHA+o2LyMECdOg 142886089970163885609957244378225169093559131065687633458877059657380607541767850701139140472705242750285722732461954100519608059127637509286558848391554697942686619832870045594188204522385787253648018847569919409782188708374165437385572046835539379151066214153911415525465041951116179326632238059135825466272 AMvXeHCaa+zk5VdB27KoS8XpjSUngaw7Gwlq6e2RrkEOxBhU2rGWGJ3fhq1HBNRxDf0quqfYTMd1speisaEr3cIyx9BhYwB6A+Nex/Sf9DSixezhcgEz6c5CfwUYP0QTTOiZDqzz+GcjKikjN7DKJTO0WSXMRG8qX8FBbH0rlc9l 143142496664357119491819741364830737485524654099662921673419335301323845847085335210884201567922636945282124120681371777665458057821603161276185071778040317947168899788341482064834489328957963447735297898161379277478278414388733161844053774747425459239004132791029364174047523473372650441001639174571312926565 AMxoMXHfE2i4khsAkv/lPtLQhbWUjP3kxYmlJkpacpicBB6z/TmG5zjmTC/sqzBvBn3J4UvMzKYFyk9/l7Wnuc480500a3S4HRVtMtirPueV8v/SPktL67eN2zoj1VZA/Rex0aRGjW2CzEKGwEn3G2bZSgdT8hKv7AypF69ppjz6 143539479941314279463880342636704987025205547180882175105616955926182352311179043850344463145750154442573797875223178075233807385237935671604701513551125937539235111702655902037518920150424691586943553275517626347557879039695678271564616114192941679606063184290901862703975921261779714258077775731727612132602 ODvOKg7l9RCn5CePG1FfMitkR5l9+7JK67eU+WeA5p1YXCcKS8GbYAKCtXPD2QfxmQcrNYfAc6Yb/kksaq29oW7MzZuTDzK0HXY5xBc/fJzEuvU51gaI0PR3cuU1qRlLqwmIlyt16gto+2E64BgPgIKJcAjx+TfH/EqNeJ77/W4= 39488587053253042573878502921384752550143716864908041972426777545317969264945056510991363961916339225192727727267483337259701961148978214005913510275048195308792987888118270387288989623193626554910652030960235845935461155296845475356011099372367616732243132816329531758943935324760665826550992788664237161838 AKkznyQtB+PGvbVroM5nUIzhJUjiNj7q4fC9sSFbmDgvehnwPElVlie6PimH2FKonGV4GSaxZ+osil+9omfkb4rO3pq8fy5KcFSw/gs09X/U2eEEcUt/4oSbjs2NaMIxQftM2CauULiwfkWdkMFTBkHnh7Bbyocc8dtmrBDdoI8a 118817437232756222334188081193205110010964766506378146125932730686679941224328135190204402802650523704343176483564284220367074983943319572348376466341132480772885833789613392397284313483009178508647973749522358005819092779831781339778163122774381387989185969990310049504391258988402795259963134610905036263194 AJfwWA7XnYbTjlJt+9hO/Q/OubHkUkyMYrN6Jd0cN5MG9Rg8W3i8U6oJxT18p4XozkiOgPlF1lE7hIAW9KRKJKGTue+iw0okLq5UNMu2Ha6l5/wzKi0QzRVTBnQm2zjPlQpgUorBBty5mcbt/B/Y3vOE4I3iVXklVtjQ7zIBHaNK 106695084438708194568048926154027115609888551145480521213711726807296356271397749432698558860759334362315257102647885062353922543502466463770991058956633500180245599467233361812610650830611712448187310827443315947425061886163301613989593906515923245020641415290300558869209909418659128196109640872398602216266 aCXItk5XhuNrbrqJr1Qm04U4y4AzSKDMms11PgVcdf5fCGdizibh6/oZqx5OitM26nRz2vob8F+ZIP0CIyIJU0T1M50dVTbbpwuVNdv/XI6gHekQt0d2g34x1TQJIcsT1VWwGWTPNMtht1hezBAYxwv105AGKnqdLiz04YAdEk0= 73134927546833985031652237686088635686032103401394612286045377544136784429757461671691980910279873140130943470029643791712859175007885735170485461366406852784845528918253441791024065848540598601036357817496637108534035807393364939272891745520961269029038360205258229770737579266643408540634722493263322616397 APNeoaWlyNa554OtHP8F7GAY5V9F7LMoF2ssg5wBmsgGFktrRH1C4FdyD0COrzIb0Vcko1/HiTnA9JXlfGKc3gTHEnO0gxBSDjK41L+EIgUfR0EhAD9iftTaCoBM7qZN3R1MYrSz3sevQZNMFOOnRrzwWEXnJaPKAZXvsqPzOIF9 170899982929163229592439208307232242235219591108657660041403142612622997092685093132858257827585941687488772925553142105567685213341947938835403410054637382864108739466539574004149772568683507025358331323655651148107044968424043673850583150424463706583215452211942132017052425497789362680979074312857823248765 ALhwBfBYpOk1pfJcNut0C2fEAd4hhYU03/ZQBqVe/7MgpEDjro7oMvSdba5kjH/VBssmZVqpvuZ5lG+vI9lXLukhwRKJg7m67HG8lZXvjDmjU/PCjxBPNt5r8/DziETYmMa+fhaMTw4hedZcwDe37t1VPIflvM94sBKu6be9yJAn 129516480651398210587505113546142851617282590236388547627336279692965778911450075230961856270046942312918567973875005814982283590898552829322178788678196583244198944578081007477482775130405341039067711963061287597331433268366003672643052056973656674139309732186091974604170508497340243515339072325943686631463 c9vpoiZvtnj71b8XguD67WayOF57QgOX4V4L++nG2u/RY9VT2+0tJ/C4NIawVa7ScQZAPVLuhV4J50HJX7FZgtY5n+lwMzNo0av7i0IqTS+1BBO8eNJy2wkCbWWBxNybuNnF6OK7eXdPb2Mmwm2OmhN2/j7HAr0cD7rK/Hnif7I= 81358980280155473712258342299472964374474635149963153129588784719499494479288254287754874893180126149146558961101860327826747785201363745989346818037655063262173536227595206355647880155693272153902647256175878517626925488264893732295267833614283963802283320574654949992393798458265266551024756663538388467634 APArEXNLzDydcHrieLDReJryWxFzcsN1dxjpJIVGeJp6itsJOrUtnmXVnETtaZhWsmN3/Zh0R7TgJ253f7PZ/Z2xCEdqF0hs2MmnERSywdWZQ0a0McbDUUaDjBNYFht1wvS6djbI1b8RfayrnEZ0miYdzrrP1ntU+5cM1QBAvj6T 168651870043094856205824264282870999215855903395882323164614939540734011037112413507417141209480771157672307388419164831992909066097194364645695794831939514470650008210390333649278806163193463937050083854756730458780288720541495880958909249273048328511615821480782977316719631334570687241232556472064072892051 RhGyx6xibf0OvY1XjnmX5na3G7emG8PWbvEa1kIjR6pK6K1MrMZnxFefXpHWInFS7ADESNI9LHjZB8VW5QrjRVPMksgdEAlkhY7MyQxaclUlShFl2AfKYBfIIro+vg7mUMzMctD+07BLk+jejRHtPVIxHmNnZrZYds80ve5z3Xw= 49204219353786910100605282012781696579642953908541693903348594981245301165936599174304121350092894937817100350990938057159324959104937469442065996667276651025661016077514839755853073999975805394464570132481314896694678249282338429544941873047382467276103868995474424700207571657816852575364781281563515280764 AKbFfU3GL6NILVyONPVD/X0tffk5HS//7FBp7n6JKMXu3VXvWnfTl32R0WyVHk2yP0iIyi6SUusSicOH9ncO8KJHmaoMGN9Fn+Zq94FTFqZne5NxHmCtwRAbFNDVGg4FeemGXEe1S5Kk1VcvWqnp+QgY0uwa7RtT8C7/T+1pZlwq 117110890075563714812929271250884717870581483065920538069845585667296154465072587148155060755111295509684258790280104272121160614620669593483929827848744548171793187278583947500205314283462739235860439216105116687015890394925743036369717346234391524403038196640934551590543386844279091801685432977718405127210 AJ0xZ9dfRc6P4W31bMHBymgOq+38ETEIMvMtr+wB5WTcsquZY1IUB4IVkrHaOo3W2SIr479IfJOOQhmvyRS4iB05yDI88Z/fJfXarkH53gDivECuo+5+JmV7e0S6gCvOuVamwoQjlK3G32bCV2946ry4EyIsVZ6Alk9xk7X5HfGU 110384671994603894282707302829898242894456931176497230904862171369974466400767175784681299142670706023468915238955836087425993929524341269289746060546848852729416925808186253355106621584826213979718185296723694190658548757311188764342751280681935289121682174507629679900374674992438818324999211250580434317716 fjzmb1D+YBU5Wn1GlwhxjiJS07k+fXxjeNRbOv5SjktzxOXmautO8xZ5ACOlYrTt5G2gzW2PU6sYNfByQ0xoUSyutOuQlD2r+8MnDrxCo6RxT3P0dUSX7q0IVj+oLK4GPbscnKLfe6KqUcYLMgKnDYnc+ztFD+csL6BQnM9WMLk= 88647261832601702291191332432291274285041869480562430895152086741320122435409959711452438332192792226899741738806447713240934608106883094466050154088410020909933636902495700779087737304255058561688767369900548260278700135161077055869478387490726087630962098228537973426295306997128615315548440548541717688505 YDg99aHkQSh9RjytWknbXzcgLD8MrWUEHF46yQLHYANKXaQYyf3yGM9TYPCDUqWbOapqQe+XfOCoACLyRg7vVDsnOPRDI9ZFUgCQBNG06ZOxzktEhnNJoRC99da8jyodFqqk2f9UD1lVa8tsQdatjUDocwgJaDAOpYEyGnUlbXo= 67567767932654827067250684965667741848878457020992905661955722020937161710030993261011062929936964216357930453809610708591260182295097124272956485574313839759737390934220465669626974544253750900911093325004172643146669082793591441922014060981070503803266774197958528843445580649512373693546027107823355522426 ANdsfO+cNtWsbT/QJHGkYAL2WCHWVPrX6oEz78pO8lUwiigVEow5roLI5Tm7GP7XffjF95z5WDxzpoam+Bfp4za75D6ZEHQmuFnpWQAmNLUHdKUE6UcsWN1rbV1uY+x+Nr5Vni/M7PfQi1yRTTJTYav40tFPb9rY48FsUotivoxd 151275723772668372472508916060743043308364940375633847663054782759325087560768667906829087958412643723335046123025802453213225972572697773468957759328009026531148112732519692142632237595562259864125679649273054426879080697360204352423668940795473103047320116317252295126635024518179060076282921965794883439709 D2Z8YA0G/vzEVVQ6itLPUC92r9n9FKRpf6lDPWIgpZOOfIkukPp7zzTlo9Ej5IsBrZBbtGz/eYmlHeZ8Y9pQj8HFW24HeKYqjmR0ujbNxI0QgoE+VUwPVg0HhoQsOGmq47zpXpkDwpOAZbMh/t1Bafq6r2zM0qmiwOacJ8KFUas= 10814483230552506566705634583020057064935800294861277580077052473134972003523900930560478187758928889017740705417070994563709463926267126567504805864719383185267204810142444719634360655595490833208838383875687102074846353850310954150927702228780599083427768247170427544730791038729428517279760042619935478187 XoZpSMHqlOyPYJS7dWSRNDJHCkjbo6+DECzu0FpB9O8bftcxan/06Twbo5d1lEqPlLx3w0XeWtrmCSCaeVcXVtlY3QuPjdKPv8LBnnhslPOVcbGyflaTPXU+ITWE6rwnIF+yWQl3NIwCV4EBtCT+3U//Dt/Ebif9gzfKpKltD6U= 66377743237695515693282032069691369056215169443985727092982918806809030742478033317158686828712146024066618073633406428345129492010236994055590530566431286733776441810601990431112187030942086686719669823512292071202675269428014136307286941704297995292544712278047959299939833088742083527714893795660235870117 QUbbkyJQ0Nru9c/nPbphM6VxHp5DWlai6407KIDbTGvUReVYI7de1gO/BFphL9GA7gDareYoMuej3/SVp8lEujXywtXzjiI+j2TzR3YYiMBAMhsJO1wU9pxy69Cj5xeFFlrOycjE9sPS9nrqnEEEFNPiK/GDDTHj0KuNbWSCLrI= 45838919357034925862751142472777409057791233610959872523563363744902783251621354580995921495295078179996083468819097423327554678806691589090814275138081407920379810144694354354954459732280968086760894209634364189264517251735804373673532012530665557440070501687207620525228416650281363557992436992284712644274 F+uI7ARCeAlnPLO1YR7RJj8LyhtE/EJMcY45lsNMff0YeENe8KOITZVxNA55FcxDYpg9sKi1UV3/ASqkqpH8MOxWpBdT2UwSX3oBkp6ETfJKqiag0C4MS8cQVsfcKF39BJ6KUE7X6KUEj11j2YIIRREmLPyZ0LatG7dN7Rmv2iI= 16797235966984072293396362937533957334369977688369659112225970370748312376722010874726300554329794854683394163379447263409228872034356195791733533528404245739693397078461712458035888813157166614479153484688995068722288153129390850561042173295997770817893349738328312152341860704179681230323810266038959856162 ALkEoXznA7BJlBIfA3Avl9kygQcxexEMApwduVRiXeYG0uEXMQU4rgMJBlPqs+ly8LTIcLFaLnJAG2KFQn2GXz2TNa7w4xkegkrslIJEtBWX/lc7VzRtcLbhaXEs0Ci1ValnW9Up7dYOj3Qw9eNo/9M9b1fD9TI+0QXFtp1ge728 129924120553920201168632484268654219915712271781591182777925696006023100660478316445751842982460082888615429513674356810187315558964251402722465707617058251479494744427428152566665405423424700027316505872162698141109433045594670140335040479559124757490095995568556894332243767736124299898808796118800328801724 Ki3FNTEE870E9GaNtbT418CLSmf++s6Di3hzAy8NgiDOFo+uuicJa54V3JNRxOBc99sl/chfZuaBQt14BFOQ0i+9rm2KD82okNABd+SNfXOb0Ow2taZX8CpkVJYDyphFPyHbPIKmzwMShNx9X2z9w4++tJgzBzGcFTPv1nhAlxc= 29618953883711174042338818332957726953262658484143534778541769862244883781157097499904047532839425875312731531093860721544220959674634750905085721866390609141599426547378130082409488797303960018348798930232014390380383063108812922828160584483043190739354817699497573863286563890071313017508437166939160221463 AJq8tcSnAq6M32ViO4hVGiHY7Tb08cLVyxpl/v0Y5adYblvjrbsFcCmsNDi5PnBOBl5awR7KZdQ1xgq6jIs+SQbccEMvJvGUZW5MgcHrXBj9XVd+8oB0z0eahqXpgYBqLDeHLU6238xR3dJYFf+Xrcrzjg8swx66OmQKkAQVJtdq 108660120968150664552423780971948386965268856900017812123107864829782135741514930439461240950044759098603910762272795612101834680870627850178371693837566833495418727543557712057554231215186486008080050486837716071537742708913279026303380104388546316647349432118287628353129105425052237438199445863950767806314 AI3mfrgcRwtE3mA12gSoQV1xyIGy/YA4pCCvja4mTjvzQOAfiZL0efadxZH5awohCC1SpZDCFsE9yYp4LugHKu/A8zMcp4k5ena8sTPDkSod1yucjybgmVJ5h17Pru28AzHQ/YUmCnojQv55aV2+AUhxzIfojY+NT2PKRqr+vuf+ 99645829268436288676280252226747461064597487404802430565833102291706103139410465131373666856042539909746769688396958963177805479987372681967013633920910376342526433530508868114301205524789149997372160919406352823342811006288909548557622230243808373083272214426118230701324879006645047374853535922112549545982 TmXQ+D8XFKSclXwnTIH8d+sb1IV0gfm7GagJahaFL6A9rvYaZ0NTizkG5DQ0RmXyo0wPmLork/296whsdNdUxVAwnGFlWWvMV0ftR1fOvN9KoT0WtVZ4Rmu6Fuc7q1PskAZzIp7MkOAxILO4iX5dNuVC+GLZYIbpTel3Ga8fXuU= 55052751096768041533898435453266875315629605001878362193939750978427494147944918632414581744895066623527980497732722163665712245580312596487741856071020477624754815927936394948233480228964159047139170955663289543349257377302556035170334384320502468579367401821986660515827461352578142560630318492817238744805 EF6KIBWQiQoHOnBdJs1p+WIcAv9ILt0cnQVo+o/2niOtI0C+eFBSiNgeddhotkQFgHvGUjq8BPYgtLC8A5IFKGzXu4SYj5ziagka0hqfhVs9zVHKNx2NUoMhPDG5R7+giwEGGPOayGHVNbsBf1FBYG91+mwy8hnNbhcHSnvLGk4= 11494909948912248031301686864833544028186348338729984264372557659364976118965740281229664413031002362633393381744365783802034700038490736736266032000546393704814403638058993380993275865674190555703046732456017652317200288968188655019374159412919163798248766655991273308390043613040731449231289437754791500366 AL7wCh8tkFe07qChFAzRkrnNehvda/Teroj65X1Bmcr14+/zeJlZDObYRYBOm8YYSYNgJekcL3o9lLFE34sCMbSJgm4dGwpEVexiLVi+zc8ndnqBDSAnRqtC+3jbInm/v8l6cUvuzrUNtzXIQ/H4FrmPMiVy0EMerkMtkfw5GBsd 134080980697158076909534078193319899756347955848461100874771253577754225619652121295523443912922220564492468474647193062555347746840044705102003079330399499915801536721237211615317000955332058281901995149084303143543150689010335818219129745452688372571010816270728441637278434982752674030696337642893239393053 APunLhlblRi3bbRBwSV8dsw8h5SvT8ncAmXPnca+e1dLzrQZzL7P2OhFope0mW1MCDl2kJPiGTdK3SiYJVsAFeR3r/0z96g3oq+8uS66T6VaJym0QToMsqQF4/fUMaTo9HsukyPyOgjVIU+6TiFd3SxQKIu1/GpQWVQIP2pkHFKM 176716779397275986910036615967409090183531310366246043951791503601618945774743601662530806467045971394247287367421508126613573039423674729894091424105133906122821596079925540513892022311039293333114333317886304014722168786051080135090242879622144693440448171583324154550086458411590240882982297314605229953676 MM6B5AgdJKe5OLlPzcXwi9WhqQjx5KsnBYxxa3kWdGNTdk/IN6TVd4Ptn8lWkLm78mw3DXP4Ol1sQbIfkHRoKFUN6TaWg5aDCJBDXyHSTZI2FDc1di0Te1SwziYn0sIOe+R+rfuLuHlcT1xaZBgL6+dDLAZaZza36UEjn5i/pTs= 34273208848307582992498656582721015257885595139328466874135636009184357438445251703533153492315835793684794951576799764181908090765379592683793969576893243386892292517067596035059342970830813419330530731370385186653239446376170533147020072285887964430731437765184844167400169982662183791828762458682426369339 AJK1dx77ZA4F0sYCgRL1LKSTvjGTKBHd4QBeVnE6FKJxIow82puqtsVZ7TBxbECex+LkLQPrEbuQaVr3giUDjg0aJCE0D9ZVXCUS06qulqcCCdWgGFHXDOQzTWDn6TlJCGxtTEMbMxSlUq1q0iKZ19kwMHiT3GydBn8/G7tIYd23 103022457217861194294329435482792508957642944252832971366936865663608381648431732294396977429863681671686490913575377744795372643599438468695483808375208871881849232129651519218503507811863794426234594709451104684234156597418383183271923307418704786548452806494411689822939919114966188329657999811363991575991 fPZNsqUYBbVGA2FAiglnByxGJOZkVSpj8Y4QNW5wq6o/1e/PRwp0TLYJXIoCJRs82pAj0QDpQbHl5lCZmNxEIQP8o8xI//HCPxPIdgBJmSfm3VGetrOpqEGU0KJJqK4IsjoVpAfPFMUMOpGNz9CSvCHGk1AKrtYvrTJEKmETuig= 87751387019308584846595931543798879607048239290774788042055795835726250309378365187899578817976976035304304847968410200168743967600896348021636654074952051821111673620467434295067182213181329543946368332581250062140819766061014427755090798550122401239987766844126425179573454145697756278292448630509686471208 EmT6DUd0bxcdprYhAnycQaxm89kltJOlIOGFFRmEK90H3RhzBGr5PRVTJVqemFVpVliO1gy1nPHgqDGVNIE1GXhrhyFJU6m+HJeNcduippRe38xPCiuraRkXao79X7WAiVYUq6RIH+UIRnfTvHBgzTwjrOvKJ5853hYmGaanjh0= 12917015385266582065020051081997430892582163827812227349569911846746592973268746845211126663077128575098045461893559476227689488349263954564361736197688317585888118974603264677576027836032271531903881104937422976121352854003385726888601980526287956222142458858211589791399646989299770657341412683499692330525 APtOYyWzdY1A/YU0SGrtjPdMZA5E50Y3hJVXppwuuSk04TjXzcbu2Sqp7sMnKYbToRW4nB5p2UnaLPhTRy0yszOd1auLngW+0ttCybD6nTcVoP65gYOwXGfSEQysqKLb1OfV8kYq5Ba92Efn+CcWWWuS0wEr97W5M/Hccx9bGu0r 176473215292413922394356058789571494026727424839036665031567966488209592078148711908841964690807374236235612412767651029865069639786447019874344449598703213025389428836803984245755885691094364960118900160737925054803955567361126391353868279642836569627177281508980029006921064654964339077608785831304875404587 Vs6bjpYfFA1R/QTeCfhMuZLZ+Zxo6wxq1jFZpi5SBR1LaUwAtOAj38OJC8L7zmxSOj/RGEmJHkulI3E1MH7P7xlWbY468/azfot5fX9BgHrtptV6Q0dkBUg7H91+tcxdbm4/V0HGQGa2rZp+XK1rO+U/d0ki6iNbsCsCR+OeyvI= 60957991334776853645581868230398759578123373154273044785333939425321390401088800849629483265841435899835570419798325123273632247193463641611211088549152950252041797959644227170492417662363676228611376046334386877555777556575818860902071813120592757466883038430756577949025778080997296219236534786815367760626 GiauT9A+wmwJsFbS2OPIM6ultIbU+kT2NgACn1jFAy+vNBahdfHMCH0jJdCs5TbmKTCeiEf3ITc5TV1OSvIejJ0GRkTf80nY47TAhiP1aehZvMAv59NQHHTDUE1U4TPVYKIyFpm1V1A+JBHKJzuGrB4lvqB2ed7k4m/ZD5lFLMM= 18363925023885496669420377869542744504974590667921570026763131637088916425434675950812384919000566852243714758512996458727914094904422651029609645299422563453163291342992902510788457007623888307499601267675322986672697397389663297565071582648674012080122614260400848960757021864980761735684874056409664531651 AL/9KOZLtZu4+ZQYQsmOgbST8F4RV4N/Z+l8qsbCFlHdXHqTTkcN0chsccE/3KkVTZsAnAyJqogbAvB/RZqttaK5a8iKlOEoerUS92FVQw/42WhsVaFggR9cHVuvCD6QqclZjSBQKQzUMy0YWPWlycAZDIv96tooA+V+Fk0jbcFs 134819194171226950171930028888667967094069342154233489571728632904658607624703819928943642011918061760802468868660586005724399808048609316802502143143910585363214684061242274402109137825176291816945489430125510625857564490981683683589784133305376252294774711594646923226452625156299996630452243345104727556460 AK5x2N/4+PKlsW/fNrw76CnE+nS76Rd7Ugo3IKhMTB/IuCc5xG4MQHo5MlWE0oVkZ+Gs4CxUpvD/WCCjHHFlSxKG4mC6ehz3NVLglBt+f1RWfPkF28JPd0UaIOG3um8kG4J3JDN48PXOPP86A0H8ZYbE5+ImmXsGAcwvScUQRInU 122499245103202714319465533564374494931278163571999934877854825659720649344163774228004853964635693562785966889622928722984134944784141208867445419597834322541679973956606275877526560988151196822256754309120410807075405427166696093800381410682490767468563176131997424692783482903880902119461752084196789357012 ALZ12i0hqFhwRAikcoahYzH/BUolhgZ9Jz6adLvvTO4wk6LLOpNC/zCz+LjM7HazZomT1SqeYJ2X+WeGFLADHuWo+Gp/I3S0UEneYHKJxoU7OoOtE0mB0BCncLckHao/LmbpnQpS+Lx5bRsr0yE6oWNea6gbyRm/R0to74MI3/KK 128128022342420083856194424802390993133863171077961467523372211039771843125192435716337829530528063182315478279257832480290950255315151577221042903861075751839976362752440630888566422581799720709574650482021111126414843635330535518992034746102956214991673417580508389225948159518319625680855827280146399752842 APXxvLifWgehdwdTRAJP5KrchRzgbUsyMWKcPGm2ZkwGDJjoTl2LIOOGVFiL4CyPBxahkEHf0nMxBN5oNGX/Y4W4PuOAC8gMgHzdLkPWkpnTcyoe5DD+fQsqNuKVw9nvyB15fx8k0d6b056nfFjnnRqgybby7MSllAWSKRYRdxVm 172707950911363219032118650562553641123743396229371815589867086054370029540557395298194067635069298952836929253340374819975848769009260895874615676938511747311585257140973518651959463416682165208985512233703837931718385346209362040743041262031997793519095342415901373534535662377972036003546589624834285049190 O+9ohtZ9SzGLJoZM8IRQAjhc/GPt2X5G+M22ZidYjx9WgOTrZDXorSyxLuHxay6djsJSgjxYMj8MuanYSn/DzPWBB1Gn4cDmIsfeYuzO+vUJ4l6d0nIvBg9Iqs61/PGFd46YxhnDiVQ9HEznyTjzESnNqc0+/OkQVJcwNHAcZBg= 42087920806448980363073662127262313840530298932643042322138035915324224188032438119079107631420338701086802583985117830416851550991102672642532160807467909040086448764318690465254898516502941122327185894900817634110254371864896139724173087625913998657136384357741816102965779105122269429701537815263708996632 VJOZmvqrqsIUTQSSJpZPhbQIYN2tsfBhAciWnfAYpwjK9/ts7OP4Qgdp6T/V2EsSRPnfZ0VKdLg1CnEWDhfcODo+/BZcUrJ0AviFAEtdeUhoMSWXtjel9Ln2guHY4s33z2cN70+e8gfjes65lCzrxUIXEF4nKxzKBnScoooQP5k= 59391682001673484862915842850714742391303140646889359425353339320546979084250010101273851580028171449840778038774656177449549941659895629203970455580974953864068394275066532699748911169800076515776388213090834432354601344176559839798153004796057709798368011673585434643656820656931921831615507416411999846297 FRyJCOgPziO6RDHX1JgYGZRcSAuoQFIZM4niD/B0twK3l+TRpmVigKZAJnZZFtmX+0JQkDwQn3lcBGQIL6mgy+j0hD58U2/Wd6xebuHSzf4OHVGo1cYoqZLplszA+hVCoDVTHi2YAZ+GtfQEggumcNVxqfEZd6D9Nu//hm0t21M= 14824975573460749317081504809641216868382341402512168178334301409725840669112911061147252565570697788806398498723577368905065980113760265945344671897779830912242224090954834750057278285419880820811348943398148063418809729356397202526234113316098584002071850758705282845646489058224513019380757604894853946195 dUk5LyS7mduFJlvh5o8R73kJIeeTh0Zli/y3XjtIXfCaNRf+wDlD/pX91JEwsQ5Mvj8yq/Uq13QyWhoNwsPpXVcJtJ+02wtIn5darsBDfzcD/LbWhl7zTRUeMjZ72gAWi1djx94SWjrZJS2oWZU92Og1yOyKRG+ua0AhHfYYh6g= 82361050315899968537319599868832189063658136463903643442673674137187842597528653416212822014359684261704550279153006971937114135373937934986951573613797195556144113400128502946618028800530164890707031379614952207482505803377774320259789692177752930767589642007257364960987343146063216186985472686575891023784 AI6rejwEznR35rIPuIz0CP2aWyhRUR3unJ90YfxyuVYxrqOJQGSDTSf6SGDDw5MqpZXa9pWuwpyrb6smOq4ZtC3Er7lipJfXDjhy+0k1qcfMjmqbATUscwXGpgW+MO71cttccEz6vhbjndi8gvG5M/vfL2l1jA8nXuBd4e254dbz 100186164434910864539376019601151338080943067893748898987236087770762310617199833479771711726248130012472861788210345311298499515751355424063761182369333224929721733015910055321263016834247318907562652286587380604998130368845939290804442878127169587599285040969551065995197981341260363722618429042861484922611 AJ5vLZX0fSs8dUSBqd5hki48T9cYuR0atxR+qv7cRu9nD1vP8uNVR8dLitg3XH0RARt3ZmOgi/AuggZt6tTxuIBg+9JhBY9WW+BLL5CnYWHC3AKMi7MQBWciLtmBpyF152bDaEcV1PXxtml2KxX0Ba0C+hGVDmJSdi8Kjd4AkfU6 111256341508463539324514225759801553679558662737345522765042612717818066374840372549356543720386819501973783940451033901079765311790026584654529398345993992144903839534037331533660672892487693477412528974248713261092693018326068480417183236210881306241164169849090833681510163753605662526243408192127670285626 ZhXtSzn1GiFfHHnSKUYZiTcEWqlI8owyCKFjCQ+VEvkdk50m8uN7RCQ6ZhI545tN7Uy0WdLstJhgJETBYLHHIoWsJn07mgPxuyO0XsqNroICMQEOO/YWQFk1c0VqZifcohQAwJj7fONzM7hTcA22/7gVigJ3iLq178jZOJsEPQs= 71686982768953132894579286530164112027530221141251507987469672039995314435159469907420372652392376452531392493658576814100773556880394271726970628960571077839124343525055625420896355363707908511865700866168843075071778015504724409171911254647909938237551680861008772396291072284353858575645679153885560978699 Vc8Cw5m5yI+bJ5sUJYm/F2wyZ5x3D4ydyL0uU/3eVF2ZJu55OOlC9pUyyv7WGExClHvWpR9mhMnsqCLyseLfM2Q/YXJ7cjGPKp2xd+fvwHa4hRi1FdOxs96rJnb+HUt9hTwQByXgzpnUfs7AqrqaNf4WSlBNMu0IOOqDdB4iVHU= 60256873326783629723455608618518793848697944184579877638436234491615392142659293975260290798403892159720925893207048153291000664050780029732557737984085196691225472664027706406879051455184548871511448456651238810812870905640934953489289909009741493031472382758586341375517766302753448531830002512912250459253 QmeUn6cbpE8YrDfMETz/+KVFaK+d4NHHzcdj/MnjcmqQSLpP/XwCW/aeudlN3SfKd6rNo1XZefunZO/ek+PHEIy899WzjiJaajhf2X05fl9WuPEaMES3Yrr+ClogFNQ+9jL8+7L+J8lDuqQzvchT0U0RPay5HSNZw+ZouVCiQ18= 46630904037845609335515965570673490721137364238213103678233212262384415738654627185220187275286458759154841820256007930773120637898228224906635911124921895934056288121005350040349882413280772888907627838315559544636626856478316691755270725623680935763476199888127096014398699432042227882284223578563208692575 ALUBYIShA4w5kRUa6iNF8S33DqaprdOWjVBnO+j9CCGtUh+NNwfpKR8AKf536MtuFFtwaQvRIlkLpaTYXuRxzyU/YG2+UfRQF3pEmXQhcMxJqFzqZ5nWCIWlJ/KtYS4lcC/B7hD2UGAktnIdjVUTSxX60VzA+zxeunV2iBZXQlEs 127106299687401374061881872616647348819431126560557369258073443762502337592227172639640997680536372567116568811258505773087926491911004324918919511363985868314578663758269650473780772688462266790559846182685481907703974916356209771821075179827563487466641669110315430790405454641953880582274165368514679034156 ANyAdMnVCVjmUZGiVdyvGE5mUQpKoJOJINqMAfzVUGvvxXFmGdoAx+xsDRNAP4KoijpXk6E3yPBPBZEWyhiHnyjEkktK/gX6gnb745afS0QIlsjhKCk/W/BHXkzC862Llnc1ZGAIsERnGceEoZHdICfDUh/7nMFp5WuSMzPB7nEO 154841617115465511611746667401422322067517612306328612547616471923266281876818466022676728696273611923942543658633762267658490816264271663863494188027433799849037906883352478212451733963905925106470599843045599411842850386623187980045961158399934160107237440980574028985561404965317132715808604373199725949198 AJ4nfhDe+HojR2YrprDHW9FVUxsZvoIekwlNL2iKFRFcTB9IcEdh6QnGcaRinev7yEYUsL6saSxUj39uWlqo8udJFdszuuQUmnloIi34L5uj0m1OpLy2dawpFQr8pqyA7go4ugMMj6XCtiVnISUcK8wjHgY3Jed/EKK8k5ce0Jxt 111059703393618496515021583605572584329116596402705082562306930876194742195701060137568030171429700588269665205795898835699633817098262654446852249498668467827435829513531633390969638488553144849154126899372953755511962841193763362947708260103832329116485114451074371844037650417731807385491783373627950406765 AL+heSTflb2MkRYFTKghfzqlVQ1oE5vcx0eCIsy9NJ2NGFXCRRvoGDVoB8UEsUWIRnaA+MIpwDKGpbOS8kRQrvBvPe/xM/t3jrGkaS6pN064+bCBx8Y/Jq31ZXNG8oUol+y1Eo6fkUKNl4EOetmZWK8VmhVwol5YngDffj4Q8ned 134567692290185631768518572983694048149859804864902017394351513816079806629664302312927579302025923096596995134868068794900003728293470554490807959649153000914807604036531509869958441069678002226922395630284261949256022972967357884468325217602330254290548618134453007903724438628204981673400911693835033278365 AI272d2sbYIi637kHZC+6lievgcDvT5VKaCnus3fHwm2vfao7oYu31P4st9DlqPWJ635X6QtLkU5HgvVSy66MDj2fcOfwVL09ffkZYnoGNdhMADVgOq62Ro5cCpOdw8Ko0cCyVpVIaSysPuqY7kiClf9GTdyZz/uYHDgwWeNrc4R 99528854246023003959943182132914587584844397870416002887630245681136432049666385367430032197518895755482367603560037194955739661569172773017279832774100155646116233705958563163070414171045438199561777058338188494271322834524386565519620661180246416329082614115142485663975718653564590519408413408765689056785 AN9S8vPzo4SkyKsk07nfyD0um1riJzRqqWF9KCL+kWMHajurgPACikYzu61tL7l1mNEaIU16Ndz541o+y76DgsTLYszu4KXUOEt1Gu3eHy05Fq18zCDlNesSVjkZjPmuJr2ku+p0cP0TLLMn7/KuVOm4GlEVc6OvBNZuEzRriSYZ 156823459768092337875922818543729136404805918580285507923139232733465414368775678369646914249412830351437211620056021568154043505276475345347569200977945836210758870414054407438380975491139001471954448623922841964684437333066353208837709613982022690623722155151315252634380695513434502419141555410441456920089 AMc5H8kywLgiT4zz5xgoI90jejsHorbqUGtBeX9wke7zyvEKyWxRKScZwzRbinjDZzN48eg/30qTZOV2Rw97JFg+EA63iZ0vqfF8jErIt3hODniKX8zayCuNmiSb5kiZL0UDU1SNh8ER4m6o5vshBKkmqs0PeozfCGQtR3bZXlx4 139899247405256530335276706333424670310599977544642091674186635734421385499036688803073040921114325725234673132788498809189814711681909865484671959982394306416477300458309408833281654917008031099378445580498219376391819745965887864647387211647794422908411100892195529730435423964537342228510107659017578765432 AKv+3H/TruTX3wdMWnLzD05em8u/QMl6lCHT4VkK+uZwBXoLeji54Tcs/hZIhj0Bdj0URrRt+7JdGSTy4Sr986AtVFxBJZA3lT+JT4JSrq3oY1Tv+tX/yg8ZodQmbpQyyfaFg3BgeHNmsUoCrdqhj4IwBqEXoOBRIXnzaTuqqSEw 120779384043726135670909127168686589868907326577918074234323699599475436892003731971700278391108690400460261929381703781833059801757700386671579819341589048987186473249926590758009001670959004477454905417357202448886738669226760846888369186457452643053236389556969071303251275912453385963613554945645058007344 ANXIB+HxOyJd3YYsscMpqZpi/eYjZi5q6A0MohU4BiWEJK/E4uIObLJDH5yd4ng+hn7UMhc+R/AxG88hIdOc5NyG/QyFs95ZLUC26F9rkRifu2CBkgqR5EQi2cgwC8jGxQOkC62YND6cAn/ILsKTYaH0iavtO9Tz04vQp9Ypc82H 150122383481070201614242107655752525590609186454390549085509458064289390813495886095936526832230958746095739308601699615024239939948911472291507190108935262129646691795733786714291498653838550751365834947465294261687773081563139416397262227609481906371677917295227469553787085145970923979142676551778927103367 ZQLFoW+dJ7vrHdMlcLRGKY6T6PZKnE2L3NjXymS/55my2CDBLdDf3oXwLlRjVt9KnEiXyQzLhyY2PrFA4k3N/3P5lVDLHero5c36TMshbHgbIKRGN2CGWPEFeQ4j040IwVbQCPJeuF3jL5ikCxWZFXfeEnTL6TqumLfD9yLQfKA= 70932215714423143395949105745758445705072524008235214324766464113352968998429901322485575506330607802260244612268338586532462314021433435523464635419846126736185176246740838082062856583684393425704173881940108783636582561707441482446854068022535943408999200681879161519209676205165680598258447492092651404448 LzzvPw0FdtM2G/RRiqoajJiIH+Lw3jpL4H+08yOpp1bNITR2Aq0beu2nP0H4o2Z1/FNr2hzuGakkAhVbmmRXc8keoOkeaAQAP/8OYxHpjrqou3WPWaKx+vUCTSqVYYf8gnVKpAAC2cD+3lW+/ZJ538o+c0ovbUKNu1u1j1OBtA0= 33171669664542509840621265032202455391098253465550501094201777336478104142847268103467889435377685359857979277521589539506627375165485879405453566052091202280471235979376217319335800766353336252760793484157724210008639813552207624049019149744883918494762511376489708611103181576211531366514802868659603747853 APrGj1lIIlxA57DNh+bTEAFbJK2Y2P3MxLShb4fPx2aY6j88k3umoe07ISQLf9PzNPeml4/0I3w0KNd2x4s9KHbj7NsIT64lhO6eQSEteqZXZGXUYUyNzhrTbAjt+Q9LVKItQhsTkTW2HTQ5RQZfGrkL118b/I18J4P+T8CGZdDz 176100632478477421621142147788721746818712752858710594712903769452749028606541677227413333567013253138397373757811889654342173021761934591400685421771460440213093509170325205622261487145789848227404883040799927313402244625239515162996390018403365063394514244196976794479529075569412676472840544017222373593331 Fvcl/LemWk29I5LCjU1QedTjGlkvFF/kZXNkRJv+vNZ7qgq6pX8WB9yVkk6AoclDYAhCRfKTKuEpR23iafVuHpprPfNXcqBH8n01kq3U27xqIy2hS+D6BRBK67PQaekq31EB0aOcEb/DuNaXakS9+mtTMx6BKt+WoEY+NkzHK6c= 16126868736093163702771491576570380743773057522016869811780571865928979861357811080042796140032050364543242385458140594532945509386155523162799601656485075247603490060565663264947465987286983338572455184901756399862440455644131755848583379822279676555143231305246033911608913609591095831135803702269767527335 AKW8tvaB8YZ7J5W2lmquBniJzUhRfqFdPZPqvBoMzR4cRh1CMNdSFsYsnsaF3KolNzogdsxFpHAaEMG6zSvpNJAoi4nixCqb5SETXrSLASXvNjI9MvCoE2JCRq7kMbjPL7cem+mBPWZITGUI6KVlJPLxQngHYSFxukqlx7jznwJH 116384596458828069344020651216200368975621068920641012055593076864629080375946542748377736186556382088448816531408136815533164209947323588157210859294774679831647934533061547276394884474877353537242203645373945111105805934070657589374883764420038511061919092743520704686962593876316976299391579463759429567047 D5N2P4FrqDf7/2Z2BJsqah4SjUtolic/yNqdNzvNEogDKZKAJyGq4zhnHvkYXkEm2ueU/FDPJRqisszG0oULdU6c7p8acirEwsGLVh4RamnFRgmQSK1vbiYB3bR+P+iFX/bZ+TWjN2Y3YMa5UB//I6Zb5kEIjmTpjY2LEPI1e6s= 10937855369372570149476727082965401421189236366492771695094788039313362971972373068736123833330006002198346944149230147444718818161877123407713821100752433128205189334393732633989950841577315682292180735057952587083688644195300641998709155269462601925653013312848413290208844194513502358901613104779186502571 V/A1ktS0xrcwlI8xrYqvlLCFYrdVp8tEzZaZ9iNNpPH/pzVsA0WbnnUeHbdilkje+4OdoX9C4U2xaOuWOfvqLR0c7GeCkSffCqyf4ZsBmjy/BQL6rCpxMF0gIHXO5O8aJ1h17hy9LTuNzWm4zVh4pNFuHC9L6nAcf92udMiIQzk= 61752386563628388546439207444896778638632243226541303179646524864765343154194512297447627825411023405896612559648434895675553567405277169056807223959390559391191382555701580549902639604424290133917402316755076644943742815711432111554988540913643347167948778404861099845961151998728662878854088239266688156473 APoPgEKA0/r1FYmt/Iso6ChYK6dDU62Y+vH5h/LVE00biBYG1f7aL3GdllUTN+XQSHpqlDw8CD+9xojwZIMfgpgjOwLbbe7Aso460zLrg3R8aHBpbVt8iZUgjACwPYr5UyKbFzIAWaXcnYYQ+tCO9aDIuOz+/7eIF62C81zXFJVZ 175598490446477604563905754135475294999639698464908622773037381109011373179895295130424828038708319325919451724985361900259676699137657615076219968061941008972496322083528922054390781811699677037439989404270415929836486610353098273115864435328533577114470407444852521009919911888840405368858409835197558461785 cL54ymLJhRx3U20Y9aUTIsXy9Ags+XHy4qk3F7uJyO46eiXSL7VrrR9vTQXAbETbu1YiVWfslsPht810eUDUVaVir6yLnXkywn46Ci42FEvVoTEFjO22uYcCh8nqB8H589w/+lVSlNrcILugwfdfCvK1iZzVimOO6l3qzfXToOU= 79171550718114578361958369278761819285111811576818442980166457146638966315793211967882077899426611721874954146020093740153495693185472340728106727284441726113022873005252623222594060645383105757498856463065370975867121188445567981809371870213273555432308279508351518168027875538720367440153667708369625129189 QdQN4qW2QZq8/fmSaqlRiPSoDbhmF0oYjaY29HcKYGHdlOH0AMJb+RUIq1aszvVtjh7AYay2TNhaZMWQ6Qi3c42SNk3A1MVknT6zqiRCGjNFfxf/matbRLbTFQF832MAId708vrFLF/o2HpekMkc5hcHB6bkUUhEI1NLcMXwGck= 46226230186280253581676626651942823886592433541360244612432763620730826574920825070086312767146345247802570752482654580909236388357139147786783758670999083804670979821212991224400629053427330483809790366665043598754931511997925850227997764381723288657884346974360232490075739442406431704368767588177525348809 cxHvCK/dyVDvaqCCQyLeaiBGA36mV5el+1lc2eUTkHGUzX5gU0QQCEp+iSXNJhIOON8VFpKOFsziuV0Z+3cegWRw/VnxnjXcBh6IDKdupzOPB+Yl8MA1ti/GrQjLC6ikcNYNjQT0ZThL7KTqEvvZJH68WYmD0IuK26swjNGIGaI= 80804939616399473443737611589382762718815989847332356984276911837267997590368701684135326680567847542004499684038240485603420973682522792156533112356849436451918522884749244246467852622918805139990256619014116276456718693703261686778030658826952213058982142604346352178078750879100976710761147710018148637090 AIQ3OIZevkYoRGBmsFaXJobSfLeInuKKReVYNjP5VEPoMq0mXTltY6l09/rQ3d1JjsMD1PfA7emhxex+H9t3leBIfCi6Ux34GQEjXWpQc4awuiy9tbR077HaJyecvb8Qy1FTnOHoH5C043QJzrKYT/sFXjgB60piI8Y0R/hwxO4r 92845026347218330987427785323244729176754623818531419911990153715676845614711324345879159989637824921793015074978358052562420379797956750450245721653716740651389924718711940869162230097839047895842495414221110468446944827052871968998907462191349838598297775847512250220907563815783358238473966349820476321323 LoG6ib5lUh57rdmSkZSWzBoudytFohS4uoU/uly6OaQDOi34GeNVxu/yr6RszJyL9JWkGNgFaBIv/HirH5zA9VQAL/6kpL93a0/GQ/nuHkHy3GWZPF/2+yJ0PfazQ40fWhHZfRxBngWslbguFPjj1XaJ37YzpQAYb/+QcUai9ic= 32658152290878644668906121702816147999633088014476055330179597550087921141413344679134407016170035735846077181424615228657687216737432274043674411132745299610950657139041836412322040866250189120286839287690983293111362228893996267791120043532014262644480689231457941173330523718758287779526551822788227954215 AKu2jgOQCCfYZ3CLkXEH44aO4TtwMPeK/eq4FtNj9HZ9FxT0LLNJh0ZXPOaPJjgznvIw5C7/hNm7rUs1JeV8I8dj3nbS3EVERQz1gc/ckYB3H1bViWREOD5+TScDusi86YO/z4ar3dauKkg5kT1kKDuU/OP5kNMWvtJjHc4Vd3L3 120581042599355202025471829872601846477331097842315143148145881424071317426176264583672725691485724160094190478865850305422057632110749683552966861219554215519032344086824849470294473808177223497912069335635933312949412445851201918768630656712413082629164792850095444166888072453190903931430551124946191872759 ANLs7OsR7oBM5jSjVADrk+Mx9d0TeieTIkxwWiJ5STKNQmW2EzPOjgbfcLhbYEhzzDFJveXO2dzz6/c8V5oW2yqg7VMx88DzEbpQnQpk/rOQRw9jbI4fxXNJHkNZCeysEVvFfLJb4ecsGA0xJ3Aylny/jP10ahPv2z5K99edGZSU 148116916208650944522110872759145096907599612943009577897396622287067669897712748449324334650112672914917664881091633448764667172850435775162090891556266912697811031318228334453406561952979778127173704706529448647577013482442758465809198730066784986763500579667100246958959793527011919373534159474250508506260 AL+Er3n1qj+SBsZVtOMJYg4m0CN+DE6gRnC1F7nPvd2XnBe+QE0+LKfcpUDHVNxoydW4BDzNVwnUNbyjXZ+iuddPtO9hchVEI36UiuL0ydeldFpOZ9mtHJaAF6abd0MlHw4vXRf8CbOvXb5N4s76ggijlZBjRtU563sSmBcyq6Zt 134488725667189507159811764480908602790838430340670328479145818969651133017546803581865897303917708192047926432630297993507146075655594931523561067937580218599890162311074002344315818494246433967228889645359283635389151927472221799543158424012020308449895562192866672439712148770104592027035768027605661099629 AK/04XOBSjjPpuFXTDF82RNWnKqZz9mJQbS2B5bn0ehFnBa6j+B+MazX+AxXTL/d5+hPLT1uexcnSMl3DcGGwKipOXg7Dtuj3pfJXHTrCqXAUYrIXI+8vKVQO55yQPGfzIg9SVgetwW1sDk+a28ZhJ5a9OddqNoi5C+dLce7ZtNb 123560902006294001923570614486104726169564351074482936927091682096999779538353161007361361829586988452098646362280351148131540524964916445100589671458589346440250329883789099771417949746709217272531950438336245613419967556433467843237384555807236658182067742367748737224684334525934210197178231424396818830171 PzOEGHlihiveoWFAALY+LOfkRJfm0NUF/uR6cSU/tbpGAq4onNpr+iZIzEP5o3JBLOtDC595/NBPI0fzaXl0vQvgJs6KG8iKANjsLKQjIpZBkoKhdbG9MzTVQuAeuDW0w3sn2iMZ/v2dgAzRwfqmQYXJr3I2BbcwWraIJuZXw5A= 44381416070253681813077725822442106641846565789204187691647505370231831464947935035197059366680327425453811558282831465960889061956588244308214943856009686127871667376028831540813257349779756631357122923723235595360268572998278795110672666089470210929411514949652537714634611421849780859192966935514197771152 APnuduN01GS9dO2m2uCLs400AR2lX7elOnIPC5U6e17qbukxWYzNhilZlM4kdGXAIeYpzFdSIW/gxRMZe6TXq9krFWRaaPyT2QwRfGHYnazS9F1QNYmW1zXdt+qVp0JGxmh5PyDstbP8Z3x50/E8Mb0gLLPhNAvzY2Jnr9A8Q1Hy 175507868985304663005133968393406051624825489142498103948374797086106732382869120248515993626061853699363294022457032257026588816021007648668265488426495800459085474654859258116280251546902009156490112550154951965894022789029787886785376415437170872937201839249103828294508088966180386198213606090453461193202 QHEhL4iVzNdUsfG0izTEepwTOvxka8t/9MwuF1Ey6kxsI+ry4g4sJPgR2xMnbtOmvQn2NitAkfvA8JPCiL7a8+gmf+DVRDjKDfpfrtgAVmo+3rH+uJYTrKhAp8R7ggU2xIrvbIrgeUj7ieThPI3Rtap+IdkPCL853JC/+oKtytM= 45252649968839515171157821292772647085425694172492111870169593872127007254353374581972876464918186509502070064028725519394859148593053614163356612260257013360168930649423732336969778875205250872728821432415158634190866775855521719727700464116412886964736859295086745723651735554245035077902615220578218265299 APeaekK4mVhEShCfM0mkRebcg1Iq5CgrFIEGOoh1nHzgebr5A9Wrhm9yD1Vd3e+fFD9urDRB4y5MHPJHX1U2NFToC+H8nQkFXL8bfd/9Wl2c7y8m0Mxwi53pLIdzETLbbfeOOtJvuSYYT3n8+/PeMnJ46UD8OfqtnFuS0/bVpFLS 173873040145444066957050580959132871919216036714423404143335635770937773583761934638398867981658394368476005882852706046614562314432695052874974848076542261910660410561876043187368112065303981001507235893831108658530338308496461162623683138693880482650786841100027392293758260448606244283355655751440485602002 FqC/wgZDPTUoObPFSH5w4QR79zj/O+ZiHGTEnsBMwNZD3Gl/ClRDIsFMDDupNLgwgXsqCQbpwSOHOtAvUuAFwRpzt5B7lwIgtP5ism/AZRno5p+9WVSmUAM3glHsNtvYydz2MkXtnXzSMIR1ZVoLrdwMnckE4pbMzggqz+JZqxw= 15889870005716350976759704672045310928616256175405784574141006779373730686049218680335525720670897894546334915362899913262232170795516176419192840427996647372619000239408311568577050460995518058850793096827271653902583271225799114408537346367483775593212272587811309978019791973449354003275559762102731778844 AJXNbv2AMWadF5h99ZAUy5gLnVK/hMaakFo0ZedtPNRJobxPmwj+h52G+Czd0U48G0V0wpdeUJC9v/4BhjzhCvNhNsdAT1+vQXDuteYQ1aspsEKLQ6b+NknO88QSbRJw53+KeOY2xe7PKOa4V89XnFFBF7wljRnIYrM8vvcqVQDk 105194875227030598769888785590198577650278341586165110611689226597424766274486797264032300493674927704016605741286512271390703088626381669060095573361828932336327125438452066548897528158329044309005232090053420259033538936293519762277428283316506398965916381374819450858053512398634116052299066189424983605476 AIDRnUpBHepjBqYAlU4MG/8JxzX1mPxVNHpWvnEVgvqTQx/bisFPpXrYs3jAKIR/lzevYwhH0K/8Vvw4NK9iTMFqgSnU44AZztKsoxUXsEsl1UU56UscY5C7ciKU6vjjWI7nm/uHNOXdE82TQXkk2WX8ferNqZU5DaLFCb+zxb7w 90459642084794142567976043425270153270545560059973413835786695756473295513758287577749768786155290305189883600338986370836806413936196854410098516254596146039255388020628703824195128439558127783534033672712705194483515442668075394018677699876614329419492391568463215822656901183478205197671375262145069825776 AIdvVNzJqWPgAShvi3GhbhMQft+SLigKGrhoqas2Saz/bA9u9Td6fAxa2LjrAqshW6cnm2aalc3Yv6RW/Y8vg7Ho31NSaRjT4zMUenykcC0/Y88UNxREi85wdnHwGytms6Lq49H8/7EFGJIyL1PLRWPmZn6XFkegscI/HUq/hiKm 95105613103051650721863964216778532448106311156426028879315612217763044797186635476805213120469258258125661666950525364331551671653846368977016286153840829836509696804585927581668281228810410814602664419962214359687545209312836366693384158782798559255789953908588601637765910472073600954502095647132310971046 DdchOPjXrI6lpV84IdKCisPmdqZan8AARXRLADEhixsfXCYuO+WhNatI/fM1vgv+/TxwwIQjIfG1vOZcB36JUfjHYdItYQ70vUXaVFdpqvoBGyfOTU50Ds/11iGPCF8mWiQwR30/XAXytqDZtaVJVWsgHD3RigBSnSHhnvZAWYg= 9719024770319024562623340689338530708271347986326272393419504304391837979619189392867902307307106771234732135400958362219711925045600118964223238147375808749507928768896918369395426933218443166133187066167663170936604731896932630589251946733237697936733924510107175304126061649311812536190882160340308613512 I+Z6rdTOt26/v3dtUP1plITb15fjb6aMDvqFS3AD1+nxBqnnk7ISGE9j6dv762EIWQpMzcCG5NCCq35KOHEwRXP28zup6olOMt3CBFgYVcBE2pWOpGiO19G/iFweYZXZPY5HgIkex7HBbb7l6HhomPc2sLL/IRhh2oogyHx2JMM= 25210054612455888156900839678249806510561198051210010474517915819801056434402727631042894881559517808906460418029149538469607239850657781476308872923928122553395468026744382526167194202058040459679991391557937527079948356545086684521068912222036707113005006607012596093923970784177288565193670152033981048003 ALbBoyelCs4UkfnPjMT3S67ujhBHBEE0uxLx6kSGZq2IOMU/QdWYPFElRgYC/y++334FSEycjS6NAJJo2ITpZCO5AjNJ93J3WYgbDLiwu1VzKHX6ItfFNEk45km+QTi07+pDKcKNd1k0mxqpLd/PuZd5hRpPDDoKBb6i+mrCb2yF 128335905497646745013379107761994003743181143126608677203818152878840562628631384684712779135591095534911406031545494164782375276574093777950840330452805743803067864740000758175436633463846967335728314347497013853264454015790847388463800323796888198433722196292529074568758149650782323407298620158495364705413 ANwlxEkeqmqYTxw1ZwMi1v2wo4ntPaEYZYoTLTJQfa+kuIksnHW9va243HAiOixd+rviVdm1dEwzESBbX0wiJNtRBpP+bnRxy4xOBjNoOB0c/tfka5JVwu5eeskyHx4V3inLviUaj86Yck42n5NaJFMfBvhzVftZ/YF9WBITI8g6 154592850289860621115358362871905683265658659789986179554827712019629689749439795961607030363152337159590319622241556795951071651584979664762468782303706550885785493534656062553770262954861884613383561063525714923031691298088562054236178003658891902606245782350998076658704876516153027797371814038658244397114 ruby-openid-2.7.0debian.orig/test/data/test1-parsehtml.txt0000644000175000017500000000670212512544714023007 0ustar sbadiasbadiafound found found found found found found found None Name: Link inside comment inside head inside html Name: Link inside of head after short head Name: Plain vanilla Link: Name: Ignore tags in the namespace Link*: Name: Short link tag Link: Name: Spaces in the HTML tag Link: Name: Spaces in the head tag Link: Name: Spaces in the link tag Link: Name: No whitespace Link: Name: Closed head tag Link: Name: One good, one bad (after close head) Link: Name: One good, one bad (after open body) Link: Name: ill formed (missing close head) Link: Name: Ill formed (no close head, link after ) Link: Name: Ignore random tags inside of html Link: <link> Name: case-folding Link*: <HtMl> <hEaD> <LiNk> Name: unexpected tags Link: <butternut> <html> <summer> <head> <turban> <link> Name: un-closed script tags Link*: <html> <head> <script> <link> Name: un-closed script tags (no whitespace) Link*: <html><head><script><link> Name: un-closed comment Link*: <html> <head> <!-- <link> Name: un-closed CDATA Link*: <html> <head> <![CDATA[ <link> Name: cdata-like Link*: <html> <head> <![ACORN[ <link> ]]> Name: comment close only Link: <html> <head> <link> --> Name: Vanilla, two links Link: Link: <html> <head> <link> <link> Name: extra tag, two links Link: Link: <html> <gold nugget> <head> <link> <link> Name: case-fold, body ends, two links Link: Link*: <html> <head> <link> <LiNk> <body> <link> Name: simple, non-quoted rel Link: rel=openid.server <html><head><link rel=openid.server> Name: short tag has rel Link: rel=openid.server <html><head><link rel=openid.server/> Name: short tag w/space has rel Link: rel=openid.server <html><head><link rel=openid.server /> Name: extra non-attribute, has rel Link: rel=openid.server hubbard*=hubbard <html><head><link hubbard rel=openid.server> Name: non-attr, has rel, short Link: rel=openid.server hubbard*=hubbard <html><head><link hubbard rel=openid.server/> Name: non-attr, has rel, short, space Link: rel=openid.server hubbard*=hubbard <html><head><link hubbard rel=openid.server /> Name: misplaced slash has rel Link: rel=openid.server <html><head><link / rel=openid.server> Name: quoted rel Link: rel=openid.server <html><head><link rel="openid.server"> Name: single-quoted rel Link: rel=openid.server <html><head><link rel='openid.server'> Name: two links w/ rel Link: x=y Link: a=b <html><head><link x=y><link a=b> Name: non-entity Link: x=&y <html><head><link x=&y> Name: quoted non-entity Link: x=&y <html><head><link x="&y"> Name: quoted entity Link: x=& <html><head><link x="&"> Name: entity not processed Link: x= <html><head><link x=""> Name: < Link: x=< <html><head><link x="<"> Name: > Link: x=> <html><head><link x=">"> Name: " Link: x=" <html><head><link x="""> Name: &" Link: x=&" <html><head><link x="&""> Name: mixed entity and non-entity Link: x=&"…> <html><head><link x="&"…>"> Name: mixed entity and non-entity (w/normal chars) Link: x=x&"…>x <html><head><link x="x&"…>x"> Name: broken tags Link*: x=y Link*: x=y< <html><head><link x=y<> Name: missing close pointy Link*: x=y Link*: x=y<link z=y Link*: z=y <html><head><link x=y<link z=y /> Name: missing attribute value Link: x=y y*=y Link: x=y <html><head><link x=y y=><link x=y /> Name: Missing close pointy (no following) Link*: x=y <html><head><link x=y Name: Should be quoted Link*: x=< <html><head><link x="<"> Name: Should be quoted (2) Link*: x=> Link*: x=x <html><head><link x=">"> Name: Repeated attribute Link: x=y <html><head><link x=z x=y> Name: Repeated attribute (2) Link: x=y <html><head><link x=y x=y> Name: Two attributes Link: x=y y=z <html><head><link x=y y=z> Name: Well-formed link rel="openid.server" Link: rel=openid.server href=http://www.myopenid.com/server <html> <head> <link rel="openid.server" href="http://www.myopenid.com/server" /> </head> </html> Name: Well-formed link rel="openid.server" and "openid.delegate" Link: rel=openid.server href=http://www.myopenid.com/server Link: rel=openid.delegate href=http://example.myopenid.com/ <html><head><link rel="openid.server" href="http://www.myopenid.com/server" /> <link rel="openid.delegate" href="http://example.myopenid.com/" /> </head></html> Name: from brian's livejournal page Link: rel=stylesheet href=http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711 type=text/css Link: rel=openid.server href=http://www.livejournal.com/openid/server.bml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" href="http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711" type="text/css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="foaf:maker" content="foaf:mbox_sha1sum '12f8abdacb5b1a806711e23249da592c0d316260'" /> <meta name="robots" content="noindex, nofollow, noarchive" /> <meta name="googlebot" content="nosnippet" /> <link rel="openid.server" href="http://www.livejournal.com/openid/server.bml" /> <title>Brian Name: non-ascii (Latin-1 or UTF8) Link: x=® ruby-openid-2.7.0debian.orig/test/data/test_xrds/0000755000175000017500000000000012512544714021223 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/test/data/test_xrds/spoof1.xrds0000644000175000017500000000126412512544714023337 0ustar sbadiasbadia *keturn xri://= !E4 =!E4 xri://$res*auth*($v*2.0) http://keturn.example.com/resolve/ =!E4 *isDrummond =!E4 !D2 =!D2 http://openid.net/signon/1.0 http://keturn.example.com/openid ruby-openid-2.7.0debian.orig/test/data/test_xrds/delegated-20060809.xrds0000644000175000017500000000234212512544714024752 0ustar sbadiasbadia *ootao 2006-08-09T22:07:13.000Z xri://@ !5BAD.2AA.3C72.AF46 @!5BAD.2AA.3C72.AF46 xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@ootao/ http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ *test1 SUCCESS xri://!!1003 !0000.0000.3B9A.CA01 @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ ruby-openid-2.7.0debian.orig/test/data/test_xrds/README0000644000175000017500000000102612512544714022102 0ustar sbadiasbadiadelegated-20060809.xrds - results from proxy.xri.net, determined by Drummond and Kevin to be incorrect. delegated-20060809-r1.xrds - Drummond's 1st correction delegated-20060809-r2.xrds - Drummond's 2nd correction spoofs: keturn's (=!E4)'s attempts to log in with Drummond's i-number (=!D2) spoof1.xrds spoof2.xrds spoof3.xrds - attempt to steal @!C0!D2 by having "at least one" CanonicalID match the $res service ProviderID. ref.xrds - resolving @ootao*test.ref, which refers to a neustar XRI. ruby-openid-2.7.0debian.orig/test/data/test_xrds/not-xrds.xml0000644000175000017500000000005712512544714023525 0ustar sbadiasbadia ruby-openid-2.7.0debian.orig/test/data/test_xrds/delegated-20060809-r1.xrds0000644000175000017500000000237212512544714025275 0ustar sbadiasbadia *ootao 2006-08-09T22:07:13.000Z xri://@ !5BAD.2AA.3C72.AF46 @!5BAD.2AA.3C72.AF46 xri://$res*auth*($v*2.0) xri://!!1003 application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@ootao/ http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ *test1 SUCCESS xri://!!1003 !0000.0000.3B9A.CA01 @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ ruby-openid-2.7.0debian.orig/test/data/test_xrds/spoof2.xrds0000644000175000017500000000127212512544714023337 0ustar sbadiasbadia *keturn xri://= !E4 =!E4 xri://$res*auth*($v*2.0) http://keturn.example.com/resolve/ xri://= *isDrummond xri://= !D2 =!D2 http://openid.net/signon/1.0 http://keturn.example.com/openid ruby-openid-2.7.0debian.orig/test/data/test_xrds/=j3h.2007.11.14.xrds0000644000175000017500000000161412512544714023742 0ustar sbadiasbadia *j3h 2007-11-15T01:35:07.000Z xri://= !378C.2F61.25D6.F7EB =!378C.2F61.25D6.F7EB http://openid.net/signon/1.0 http://2idi.com/openid/ https://2idi.com/openid/ xri://+i-service*(+contact)*($v*1.0) (+contact) http://2idi.com/contact/ ruby-openid-2.7.0debian.orig/test/data/test_xrds/subsegments.xrds0000644000175000017500000000456212512544714024473 0ustar sbadiasbadia *nishitani 2007-12-25T11:33:39.000Z xri://= !E117.EF2F.454B.C707 =!E117.EF2F.454B.C707 http://openid.net/signon/1.0 xri://!!1003!103 https://linksafe.ezibroker.net/server/ xri://$res*auth*($v*2.0) xri://!!1003!103 application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/=nishitani/ xri://+i-service*(+forwarding)*($v*1.0) xri://!!1003!103 (+index) http://linksafe-forward.ezibroker.net/forwarding/ *masaki SUCCESS xri://!!1003 !0000.0000.3B9A.CA01 =!E117.EF2F.454B.C707!0000.0000.3B9A.CA01 http://openid.net/signon/1.0 xri://!!1003!103 https://linksafe.ezibroker.net/server/ xri://+i-service*(+contact)*($v*1.0) xri://!!1003!103 (+contact) http://linksafe-contact.ezibroker.net/contact/ xri://+i-service*(+forwarding)*($v*1.0) xri://!!1003!103 (+index) http://linksafe-forward.ezibroker.net/forwarding/ ruby-openid-2.7.0debian.orig/test/data/test_xrds/spoof3.xrds0000644000175000017500000000201412512544714023333 0ustar sbadiasbadia *keturn xri://@ @E4 @!E4 xri://$res*auth*($v*2.0) http://keturn.example.com/resolve/ @!E4 *is @!E4 !D2 =!C0 =!E4!01 xri://$res*auth*($v*2.0) http://keturn.example.com/resolve/ @!C0 *drummond @!C0 !D2 @!C0!D2 http://openid.net/signon/1.0 http://keturn.example.com/openid ruby-openid-2.7.0debian.orig/test/data/test_xrds/no-xrd.xml0000644000175000017500000000033512512544714023155 0ustar sbadiasbadia ruby-openid-2.7.0debian.orig/test/data/test_xrds/status222.xrds0000644000175000017500000000044412512544714023700 0ustar sbadiasbadia *x The subsegment does not exist 2006-08-18T00:02:35.000Z xri://= ruby-openid-2.7.0debian.orig/test/data/test_xrds/sometimesprefix.xrds0000644000175000017500000000243412512544714025353 0ustar sbadiasbadia *ootao 2006-08-09T22:07:13.000Z xri://@ !5BAD.2AA.3C72.AF46 xri://@!5BAD.2AA.3C72.AF46 xri://$res*auth*($v*2.0) xri://@!5BAD.2AA.3C72.AF46 application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@ootao/ http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ *test1 SUCCESS xri://@!5BAD.2AA.3C72.AF46 !0000.0000.3B9A.CA01 @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ ruby-openid-2.7.0debian.orig/test/data/test_xrds/valid-populated-xrds.xml0000644000175000017500000000231612512544714026017 0ustar sbadiasbadia http://openid.net/signon/1.0 http://www.myopenid.com/server http://josh.myopenid.com/ http://lid.netmesh.org/sso/2.0b5 http://lid.netmesh.org/2.0b5 http://mylid.net/josh http://openid.net/signon/1.0 http://www.livejournal.com/openid/server.bml http://www.livejournal.com/users/nedthealpaca/ http://typekey.com/services/1.0 joshhoyt http://openid.net/signon/1.0 http://www.schtuff.com/openid http://users.schtuff.com/josh ruby-openid-2.7.0debian.orig/test/data/test_xrds/ref.xrds0000644000175000017500000001030312512544714022676 0ustar sbadiasbadia *ootao 2006-08-15T18:56:09.000Z xri://@ !5BAD.2AA.3C72.AF46 @!5BAD.2AA.3C72.AF46 xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@ootao/ http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ *test.ref SUCCESS xri://!!1003 !0000.0000.3B9A.CA03 @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA03 @!BAE.A650.823B.2475 http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ !BAE.A650.823B.2475 2006-08-15T18:56:10.000Z xri://@ !BAE.A650.823B.2475 @!BAE.A650.823B.2475 (+wdnc) (+wdnc) http://www.tcpacompliance.us xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://dev.dready.org/cgi-bin/xri (+i-name) (+i-name) http://www.inames.net xri://+i-service*(+contact)*($v*1.0) xri://!!1001 (+contact) text/html http://www.neustar.biz !BAE.A650.823B.2475 2006-08-15T18:56:10.000Z xri://@ !BAE.A650.823B.2475 @!BAE.A650.823B.2475 (+wdnc) (+wdnc) http://www.tcpacompliance.us xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://dev.dready.org/cgi-bin/xri (+i-name) (+i-name) http://www.inames.net xri://+i-service*(+contact)*($v*1.0) xri://!!1001 (+contact) text/html http://www.neustar.biz ruby-openid-2.7.0debian.orig/test/data/test_xrds/delegated-20060809-r2.xrds0000644000175000017500000000242612512544714025276 0ustar sbadiasbadia *ootao 2006-08-09T22:07:13.000Z xri://@ !5BAD.2AA.3C72.AF46 @!5BAD.2AA.3C72.AF46 xri://$res*auth*($v*2.0) xri://@!5BAD.2AA.3C72.AF46 application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@ootao/ http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ *test1 SUCCESS xri://@!5BAD.2AA.3C72.AF46 !0000.0000.3B9A.CA01 @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ ruby-openid-2.7.0debian.orig/test/data/test_xrds/prefixsometimes.xrds0000644000175000017500000000243412512544714025353 0ustar sbadiasbadia *ootao 2006-08-09T22:07:13.000Z xri://@ !5BAD.2AA.3C72.AF46 @!5BAD.2AA.3C72.AF46 xri://$res*auth*($v*2.0) xri://@!5BAD.2AA.3C72.AF46 application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@ootao/ http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ *test1 SUCCESS xri://@!5BAD.2AA.3C72.AF46 !0000.0000.3B9A.CA01 xri://@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 http://openid.net/signon/1.0 https://linksafe.ezibroker.net/server/ ruby-openid-2.7.0debian.orig/test/data/trustroot.txt0000644000175000017500000001346112512544714022037 0ustar sbadiasbadia======================================== Trust root parsing checking ======================================== ---------------------------------------- 23: Does not parse ---------------------------------------- baz.org *.foo.com http://*.schtuff.*/ ftp://foo.com ftp://*.foo.com http://*.foo.com:80:90/ foo.*.com http://foo.*.com http://www.* http://*foo.com/ http://foo.com/invalid#fragment http://..it/ http://.it/ http://*:8081/ http://*:80 http://localhost:1900foo/ http://foo.com\/ http://π.pi.com/ http://lambda.com/Λ 5 ---------------------------------------- 14: Insane ---------------------------------------- http:/// http://*/ https://*/ http://*.com http://*.com/ https://*.com/ http://*.com.au/ http://*.co.uk/ http://*.foo.notatld/ https://*.foo.notatld/ http://*.museum/ https://*.museum/ http://www.schtuffcom/ http://it/ ---------------------------------------- 18: Sane ---------------------------------------- http://*.schtuff.com./ http://*.schtuff.com/ http://*.foo.schtuff.com/ http://*.schtuff.com http://www.schtuff.com/ http://www.schtuff.com./ http://www.schutff.com http://*.this.that.schtuff.com/ http://*.foo.com/path http://*.foo.com/path?action=foo2 http://x.foo.com/path?action=foo2 http://x.foo.com/path?action=%3D http://localhost:8081/ http://localhost:8082/?action=openid https://foo.com/ http://kink.fm/should/be/sane http://beta.lingu.no/ http://goathack.livejournal.org:8020/openid/login.bml ======================================== return_to matching ======================================== ---------------------------------------- 46: matches ---------------------------------------- http://*/ http://cnn.com/ http://*/ http://livejournal.com/ http://*/ http://met.museum/ http://localhost:8081/x?action=openid http://localhost:8081/x?action=openid http://*.foo.com http://b.foo.com http://*.foo.com http://b.foo.com/ http://*.foo.com/ http://b.foo.com http://b.foo.com http://b.foo.com http://b.foo.com http://b.foo.com/ http://b.foo.com/ http://b.foo.com http://*.b.foo.com http://b.foo.com http://*.b.foo.com http://b.foo.com/ http://*.b.foo.com/ http://b.foo.com http://*.b.foo.com http://x.b.foo.com http://*.b.foo.com http://w.x.b.foo.com http://*.bar.co.uk http://www.bar.co.uk http://*.uoregon.edu http://x.cs.uoregon.edu http://x.com/abc http://x.com/abc http://x.com/abc http://x.com/abc/def http://10.0.0.1/abc http://10.0.0.1/abc http://*.x.com http://x.com/gallery http://*.x.com http://foo.x.com/gallery http://foo.x.com http://foo.x.com/gallery/xxx http://*.x.com/gallery http://foo.x.com/gallery http://localhost:8082/?action=openid http://localhost:8082/?action=openid http://goathack.livejournal.org:8020/ http://goathack.livejournal.org:8020/openid/login.bml https://foo.com https://foo.com http://Foo.com http://foo.com http://foo.com http://Foo.com http://foo.com:80/ http://foo.com/ http://foo.com/?x=y http://foo.com/?x=y&a=b http://foo.com/x http://foo.com/x?y http://mylid.net/j3h. http://mylid.net/j3h.?x=y http://j3h.us http://j3h.us?ride=unicycle https://www.filmclans.com:443/mattmartin/FilmClans https://www.filmclans.com/mattmartin/FilmClans/Logon.aspx?nonce=BVjqSOee http://foo.com:80 http://foo.com http://foo.com http://foo.com:80 http://foo.com http://foo.com/ http://foo.com/ http://foo.com http://foo.com/ http://foo.com:80 http://foo.com:80/ http://foo.com:80/stuff http://foo.com:80/ http://foo.com/stuff http://foo.com/path http://foo.com/path/extra http://foo.com/path2 http://foo.com/path2?extra=query http://foo.com/path2 http://foo.com/path2/?extra=query http://foo.com/ HTTP://foo.com/ ---------------------------------------- 25: does not match ---------------------------------------- http://*/ ftp://foo.com/ http://*/ xxx http://foo.com/ http://oo.com/ http://*.x.com/abc http://foo.x.com http://*.x.com/abc http://*.x.com http://*.com/ http://*.com/ http://x.com/abc http://x.com/ http://x.com/abc http://x.com/a http://x.com/abc http://x.com/ab http://x.com/abc http://x.com/abcd http://*.cs.uoregon.edu http://x.uoregon.edu http://*.foo.com http://bar.com http://*.foo.com http://www.bar.com http://*.bar.co.uk http://xxx.co.uk https://foo.com http://foo.com http://foo.com https://foo.com http://foo.com:81 http://foo.com:80 http://foo.com/?a=b http://foo.com/?x=y http://foo.com/?a=b http://foo.com/?x=y&a=b http://foo.com/?a=b http://foo.com/ http://*.oo.com/ http://foo.com/ http://foo.com/* http://foo.com/anything http://foo.com http://foo.com:443 https://foo.com https://foo.com:80 http://foo.com/path/xev http://foo.com/path?extra=more ruby-openid-2.7.0debian.orig/test/data/urinorm.txt0000644000175000017500000000311712512544714021442 0ustar sbadiasbadiaAlready normal form http://example.com/ http://example.com/ Add a trailing slash http://example.com http://example.com/ Remove an empty port segment http://example.com:/ http://example.com/ Remove a default port segment http://example.com:80/ http://example.com/ Capitalization in host names http://wWw.exaMPLE.COm/ http://www.example.com/ Capitalization in scheme names htTP://example.com/ http://example.com/ Capitalization in percent-escaped reserved characters http://example.com/foo%2cbar http://example.com/foo%2Cbar Unescape percent-encoded unreserved characters http://example.com/foo%2Dbar%2dbaz http://example.com/foo-bar-baz remove_dot_segments example 1 http://example.com/a/b/c/./../../g http://example.com/a/g remove_dot_segments example 2 http://example.com/mid/content=5/../6 http://example.com/mid/6 remove_dot_segments: single-dot http://example.com/a/./b http://example.com/a/b remove_dot_segments: double-dot http://example.com/a/../b http://example.com/b remove_dot_segments: leading double-dot http://example.com/../b http://example.com/b remove_dot_segments: trailing single-dot http://example.com/a/. http://example.com/a/ remove_dot_segments: trailing double-dot http://example.com/a/.. http://example.com/ remove_dot_segments: trailing single-dot-slash http://example.com/a/./ http://example.com/a/ remove_dot_segments: trailing double-dot-slash http://example.com/a/../ http://example.com/ Test of all kinds of syntax-based normalization hTTPS://a/./b/../b/%63/%7bfoo%7d https://a/b/c/%7Bfoo%7D Unsupported scheme ftp://example.com/ fail Non-absolute URI http:/foo failruby-openid-2.7.0debian.orig/test/test_linkparse.rb0000644000175000017500000000607712512544714021661 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'openid/consumer/html_parse' class LinkParseTestCase < Minitest::Test include OpenID::TestDataMixin def attr_cmp(expected, found) e = expected.to_a.sort f = found.to_a.sort while (ep = e.shift) ek, ev = ep fk, fv = f.shift ok = false while ek[-1] == '*'[0] # optional entry detected if fk == ek[0...-1] and fv==ev # optional entry found ok = true break else # not found. okay, move on to next expected pair ek, ev = e.shift end if ek.nil? if fk == nil ok = true end break end end next if ok next if fk == ek and fv == ev return false end return f.empty? end def test_attrcmp good = [ [{'foo' => 'bar'},{'foo' => 'bar'}], [{'foo*' => 'bar'},{'foo' => 'bar'}], [{'foo' => 'bar', 'bam*' => 'baz'},{'foo' => 'bar'}], [{'foo' => 'bar', 'bam*' => 'baz', 'tak' => 'tal'}, {'foo' => 'bar', 'tak' => 'tal'}], ] bad = [ [{},{'foo' => 'bar'}], [{'foo' => 'bar'}, {'bam' => 'baz'}], [{'foo' => 'bar'}, {}], [{'foo*' => 'bar'},{'foo*' => 'bar'}], [{'foo' => 'bar', 'tak' => 'tal'}, {'foo' => 'bar'}] ] good.each{|c|assert(attr_cmp(c[0],c[1]),c.inspect)} bad.each{|c|assert(!attr_cmp(c[0],c[1]),c.inspect)} end def test_linkparse cases = read_data_file('linkparse.txt', false).split("\n\n\n") numtests = nil testnum = 0 cases.each {|c| headers, html = c.split("\n\n",2) expected_links = [] name = "" testnum += 1 headers.split("\n").each{|h| k,v = h.split(":",2) v = '' if v.nil? if k == "Num Tests" assert(numtests.nil?, "datafile parsing error: there can be only one NumTests") numtests = v.to_i testnum = 0 next elsif k == "Name" name = v.strip elsif k == "Link" or k == "Link*" attrs = {} v.strip.split.each{|a| kk,vv = a.split('=') attrs[kk]=vv } expected_links << [k== "Link*", attrs] else assert(false, "datafile parsing error: bad header #{h}") end } html = html.force_encoding('UTF-8') if html.respond_to? :force_encoding links = OpenID::parse_link_attrs(html) found = links.dup expected = expected_links.dup while(fl = found.shift) optional, el = expected.shift while optional and !attr_cmp(el, fl) and not expected.empty? optional, el = expected.shift end assert(attr_cmp(el,fl), "#{name}: #{fl.inspect} does not match #{el.inspect}") end } assert_equal(numtests, testnum, "Number of tests") # test handling of invalid UTF-8 byte sequences if "".respond_to? :force_encoding html = "hello joel\255".force_encoding('UTF-8') else html = "hello joel\255" end OpenID::parse_link_attrs(html) end end ruby-openid-2.7.0debian.orig/test/test_util.rb0000644000175000017500000000765212512544714020646 0ustar sbadiasbadia# encoding: ASCII-8BIT require "minitest/autorun" require "openid/util" module OpenID class UtilTestCase < Minitest::Test def test_base64 cases = [ "", "\000", "\001", "\000" * 100, (0...256).collect{ |i| i.chr }.join('') ] cases.each do |c| encoded = Util.to_base64(c) decoded = Util.from_base64(encoded) assert(c == decoded) end end def test_base64_valid [["foos", "~\212,"], ["++++", "\373\357\276"], ["/+==", "\377"], ["", ""], ["FOOSBALL", "\024\343\222\004\002\313"], ["FoosBL==", "\026\212,\004"], ["Foos\nBall", "\026\212,\005\251e"], ["Foo\r\ns\nBall", "\026\212,\005\251e"] ].each do | input, expected | assert_equal(expected, Util.from_base64(input)) end end def test_base64_invalid ['!', 'Foos!', 'Balls', 'B===', 'Foos Ball', '=foo', ].each do |invalid_input| assert_raises(ArgumentError) do Util.from_base64(invalid_input) end end end def test_append_args() simple = 'http://www.example.com/' cases = [ ['empty list', [simple, []], simple], ['empty dict', [simple, {}], simple], ['one list', [simple, [['a', 'b']]], simple + '?a=b'], ['one dict', [simple, {'a' => 'b'}], simple + '?a=b'], ['two list (same)', [simple, [['a', 'b'], ['a', 'c']]], simple + '?a=b&a=c'], ['two list', [simple, [['a', 'b'], ['b', 'c']]], simple + '?a=b&b=c'], ['two list (order)', [simple, [['b', 'c'], ['a', 'b']]], simple + '?b=c&a=b'], ['two dict [order]', [simple, {'b' => 'c', 'a' => 'b'}], simple + '?a=b&b=c'], ['args exist [empty]', [simple + '?stuff=bother', []], simple + '?stuff=bother'], ['escape', [simple, [['=', '=']]], simple + '?%3D=%3D'], ['escape [URL]', [simple, [['this_url', simple]]], simple + '?this_url=http%3A%2F%2Fwww.example.com%2F'], ['use dots', [simple, [['openid.stuff', 'bother']]], simple + '?openid.stuff=bother'], ['args exist', [simple + '?stuff=bother', [['ack', 'ack']]], simple + '?stuff=bother&ack=ack'], ['args exist', [simple + '?stuff=bother', [['ack', 'ack']]], simple + '?stuff=bother&ack=ack'], ['args exist [dict]', [simple + '?stuff=bother', {'ack' => 'ack'}], simple + '?stuff=bother&ack=ack'], ['args exist [dict 2]', [simple + '?stuff=bother', {'ack' => 'ack', 'zebra' => 'lion'}], simple + '?stuff=bother&ack=ack&zebra=lion'], ['three args [dict]', [simple, {'stuff' => 'bother', 'ack' => 'ack', 'zebra' => 'lion'}], simple + '?ack=ack&stuff=bother&zebra=lion'], ['three args [list]', [simple, [['stuff', 'bother'], ['ack', 'ack'], ['zebra', 'lion']]], simple + '?stuff=bother&ack=ack&zebra=lion'], ] cases.each { |name, args, expected| url, pairs = args actual = Util.append_args(url, pairs) msg = "[#{name}] Expected: #{expected}, actual: #{actual}" assert_equal(expected, actual, msg) } end def test_parse_query assert_equal({'foo'=>'bar'}, Util.parse_query('foo=bar')) end end end ruby-openid-2.7.0debian.orig/test/test_cryptutil.rb0000644000175000017500000000623412512544714021723 0ustar sbadiasbadia# coding: ASCII-8BIT require "minitest/autorun" require "openid/cryptutil" require "pathname" class CryptUtilTestCase < Minitest::Test BIG = 2 ** 256 def test_rand # If this is not true, the rest of our test won't work assert(BIG.is_a?(Bignum)) # It's possible that these will be small enough for fixnums, but # extraorindarily unlikely. a = OpenID::CryptUtil.rand(BIG) b = OpenID::CryptUtil.rand(BIG) assert(a.is_a?(Bignum)) assert(b.is_a?(Bignum)) refute_equal(a, b) end def test_rand_doesnt_depend_on_srand Kernel.srand(1) a = OpenID::CryptUtil.rand(BIG) Kernel.srand(1) b = OpenID::CryptUtil.rand(BIG) refute_equal(a, b) end def test_random_binary_convert (0..500).each do n = (0..10).inject(0) {|sum, element| sum + OpenID::CryptUtil.rand(BIG) } s = OpenID::CryptUtil.num_to_binary n assert(s.is_a?(String)) n_converted_back = OpenID::CryptUtil.binary_to_num(s) assert_equal(n, n_converted_back) end end def test_enumerated_binary_convert { "\x00" => 0, "\x01" => 1, "\x7F" => 127, "\x00\xFF" => 255, "\x00\x80" => 128, "\x00\x81" => 129, "\x00\x80\x00" => 32768, "OpenID is cool" => 1611215304203901150134421257416556, }.each do |str, num| num_prime = OpenID::CryptUtil.binary_to_num(str) str_prime = OpenID::CryptUtil.num_to_binary(num) assert_equal(num, num_prime) assert_equal(str, str_prime) end end def with_n2b64 test_dir = Pathname.new(__FILE__).dirname filename = test_dir.join('data', 'n2b64') File.open(filename) do |file| file.each_line do |line| base64, base10 = line.chomp.split yield base64, base10.to_i end end end def test_base64_to_num with_n2b64 do |base64, num| assert_equal(num, OpenID::CryptUtil.base64_to_num(base64)) end end def test_base64_to_num_invalid assert_raises(ArgumentError) { OpenID::CryptUtil.base64_to_num('!@#$') } end def test_num_to_base64 with_n2b64 do |base64, num| assert_equal(base64, OpenID::CryptUtil.num_to_base64(num)) end end def test_randomstring s1 = OpenID::CryptUtil.random_string(42) assert_equal(42, s1.length) s2 = OpenID::CryptUtil.random_string(42) assert_equal(42, s2.length) refute_equal(s1, s2) end def test_randomstring_population s1 = OpenID::CryptUtil.random_string(42, "XO") assert_match(/[XO]{42}/, s1) end def test_sha1 assert_equal("\x11\xf6\xad\x8e\xc5*)\x84\xab\xaa\xfd|;Qe\x03x\\ r", OpenID::CryptUtil.sha1('x')) end def test_hmac_sha1 assert_equal("\x8bo\xf7O\xa7\x18*\x90\xac ah\x16\xf7\xb8\x81JB\x9f|", OpenID::CryptUtil.hmac_sha1('x', 'x')) end def test_sha256 assert_equal("-q\x16B\xb7&\xb0D\x01b|\xa9\xfb\xac2\xf5\xc8S\x0f\xb1\x90<\xc4\xdb\x02%\x87\x17\x92\x1aH\x81", OpenID::CryptUtil.sha256('x')) end def test_hmac_sha256 assert_equal("\x94{\xd2w\xb2\xd3\\\xfc\x07\xfb\xc7\xe3b\xf2iuXz1\xf8:}\xffx\x8f\xda\xc1\xfaC\xc4\xb2\x87", OpenID::CryptUtil.hmac_sha256('x', 'x')) end end ruby-openid-2.7.0debian.orig/test/test_parsehtml.rb0000644000175000017500000000425412512544714021663 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "openid/yadis/parsehtml" module OpenID class ParseHTMLTestCase < Minitest::Test include OpenID::TestDataMixin def test_parsehtml reserved_values = ['None', 'EOF'] chunks = read_data_file('test1-parsehtml.txt', false).split("\f\n") chunks.each{|c| expected, html = c.split("\n", 2) found = Yadis::html_yadis_location(html) assert(!reserved_values.member?(found)) # this case is a little hard to detect and the distinction # seems unimportant expected = "None" if expected == "EOF" found = "None" if found.nil? assert_equal(expected, found, html.split("\n",2)[0]) } end end # the HTML tokenizer test class TC_TestHTMLTokenizer < Minitest::Test def test_bad_link toke = HTMLTokenizer.new("

foo

") assert("http://bad.com/link" == toke.getTag("a").attr_hash['href']) end def test_namespace toke = HTMLTokenizer.new("") assert("http://www.com/foo" == toke.getTag("f:table").attr_hash['xmlns:f']) end def test_comment toke = HTMLTokenizer.new("") t = toke.getNextToken assert(HTMLComment == t.class) assert("comment on me" == t.contents) end def test_full page = " This is the title

This is the header

This is the paragraph, it contains links, images
are
really cool. Ok, here is some more text and another link.

" toke = HTMLTokenizer.new(page) assert("

" == toke.getTag("h1", "h2", "h3").to_s.downcase) assert(HTMLTag.new("") == toke.getTag("IMG", "A")) assert("links" == toke.getTrimmedText) assert(toke.getTag("IMG", "A").attr_hash['optional']) assert("_blank" == toke.getTag("IMG", "A").attr_hash['target']) end end end ruby-openid-2.7.0debian.orig/test/test_consumer.rb0000644000175000017500000002064312512544714021517 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "openid/consumer" module OpenID class Consumer module TestConsumer class TestLastEndpoint < Minitest::Test def test_set_get session = {} consumer = Consumer.new(session, nil) consumer.send(:last_requested_endpoint=, :endpoint) ep = consumer.send(:last_requested_endpoint) assert_equal(:endpoint, ep) ep = consumer.send(:last_requested_endpoint) assert_equal(:endpoint, ep) consumer.send(:cleanup_last_requested_endpoint) ep = consumer.send(:last_requested_endpoint) assert_equal(nil, ep) end end class TestBegin < Minitest::Test attr_accessor :user_input, :anonymous, :services, :discovered_identifier, :checkid_request, :service def setup @discovered_identifier = 'http://discovered/' @user_input = 'user.input' @service = :service @services = [@service] @session = {} @anonymous = false @checkid_request = :checkid_request end def consumer test = self consumer = Consumer.new(@session, nil) consumer.extend(InstanceDefExtension) consumer.instance_def(:discover) do |identifier| test.assert_equal(test.user_input, identifier) [test.discovered_identifier, test.services] end consumer.instance_def(:begin_without_discovery) do |service, sent_anonymous| test.assert_equal(test.service, service) test.assert_equal(test.anonymous, sent_anonymous) test.checkid_request end consumer end def test_begin checkid_request = consumer.begin(@user_input, @anonymous) assert_equal(:checkid_request, checkid_request) assert_equal(['OpenID::Consumer::DiscoveredServices::'\ 'OpenID::Consumer::'], @session.keys.sort!) end def test_begin_failure @services = [] assert_raises(DiscoveryFailure) { consumer.begin(@user_input, @anonymous) } end def test_begin_fallback @services = [:service1, :service2] consumer = self.consumer @service = :service1 consumer.begin(@user_input, @anonymous) @service = :service2 consumer.begin(@user_input, @anonymous) @service = :service1 consumer.begin(@user_input, @anonymous) @service = :service2 consumer.begin(@user_input, @anonymous) end end class TestBeginWithoutDiscovery < Minitest::Test attr_reader :assoc def setup @session = {} @assoc = :assoc @service = OpenIDServiceEndpoint.new @claimed_id = 'http://claimed.id/' @service.claimed_id = @claimed_id @anonymous = false end def consumer test = self assoc_manager = Object.new assoc_manager.extend(InstanceDefExtension) assoc_manager.instance_def(:get_association) do test.assoc end consumer = Consumer.new(@session, nil) consumer.extend(InstanceDefExtension) consumer.instance_def(:association_manager) do |service| assoc_manager end consumer end def call_begin_without_discovery result = consumer.begin_without_discovery(@service, @anonymous) assert(result.instance_of?(CheckIDRequest)) assert_equal(@anonymous, result.anonymous) assert_equal(@service, consumer.send(:last_requested_endpoint)) assert_equal(result.instance_variable_get(:@assoc), @assoc) return result end def cid_name Consumer.openid1_return_to_claimed_id_name end def nonce_name Consumer.openid1_return_to_nonce_name end def test_begin_without_openid1 result = call_begin_without_discovery assert_equal(@claimed_id, result.return_to_args[cid_name]) assert_equal([cid_name, nonce_name].sort!, result.return_to_args.keys.sort!) end def test_begin_without_openid1_anonymous @anonymous = true assert_raises(ArgumentError) { call_begin_without_discovery } end def test_begin_without_openid2 @service.type_uris = [OPENID_2_0_TYPE] result = call_begin_without_discovery assert(result.return_to_args.empty?) end def test_begin_without_openid2_anonymous @anonymous = true @service.type_uris = [OPENID_2_0_TYPE] result = call_begin_without_discovery assert(result.return_to_args.empty?) end end class TestComplete < Minitest::Test def setup @session = {} @consumer = Consumer.new(@session, nil) end def test_bad_mode response = @consumer.complete({'openid.ns' => OPENID2_NS, 'openid.mode' => 'bad'}, nil) assert_equal(FAILURE, response.status) end def test_missing_mode response = @consumer.complete({'openid.ns' => OPENID2_NS}, nil) assert_equal(FAILURE, response.status) end def test_cancel response = @consumer.complete({'openid.mode' => 'cancel'}, nil) assert_equal(CANCEL, response.status) end def test_setup_needed_openid1 response = @consumer.complete({'openid.mode' => 'setup_needed'}, nil) assert_equal(FAILURE, response.status) end def test_setup_needed_openid2 setup_url = 'http://setup.url/' args = {'openid.ns' => OPENID2_NS, 'openid.mode' => 'setup_needed', 'openid.user_setup_url' => setup_url} response = @consumer.complete(args, nil) assert_equal(SETUP_NEEDED, response.status) assert_equal(setup_url, response.setup_url) end def test_idres_setup_needed_openid1 setup_url = 'http://setup.url/' args = { 'openid.user_setup_url' => setup_url, 'openid.mode' => 'id_res', } response = @consumer.complete(args, nil) assert_equal(SETUP_NEEDED, response.status) assert_equal(setup_url, response.setup_url) end def test_error contact = 'me' reference = 'thing thing' args = { 'openid.mode' => 'error', 'openid.contact' => contact, 'openid.reference' => reference, } response = @consumer.complete(args, nil) assert_equal(FAILURE, response.status) assert_equal(contact, response.contact) assert_equal(reference, response.reference) args['openid.ns'] = OPENID2_NS response = @consumer.complete(args, nil) assert_equal(FAILURE, response.status) assert_equal(contact, response.contact) assert_equal(reference, response.reference) end def test_idres_openid1 args = { 'openid.mode' => 'id_res', } endpoint = OpenIDServiceEndpoint.new endpoint.claimed_id = :test_claimed_id idres = Object.new idres.extend(InstanceDefExtension) idres.instance_def(:endpoint){endpoint} idres.instance_def(:signed_fields){:test_signed_fields} test = self @consumer.extend(InstanceDefExtension) @consumer.instance_def(:handle_idres) {|message, return_to| test.assert_equal(args, message.to_post_args) test.assert_equal(:test_return_to, return_to) idres } response = @consumer.complete(args, :test_return_to) assert_equal(SUCCESS, response.status, response.message) assert_equal(:test_claimed_id, response.identity_url) assert_equal(endpoint, response.endpoint) error_message = "In Soviet Russia, id_res handles you!" @consumer.instance_def(:handle_idres) {|message, return_to| raise ProtocolError, error_message } response = @consumer.complete(args, :test_return_to) assert_equal(FAILURE, response.status) assert_equal(error_message, response.message) end end end end end ruby-openid-2.7.0debian.orig/test/test_sreg.rb0000644000175000017500000003735312512544714020632 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/extensions/sreg' require 'openid/message' require 'openid/server' module OpenID module SReg module SRegTest SOME_DATA = { 'nickname'=>'linusaur', 'postcode'=>'12345', 'country'=>'US', 'gender'=>'M', 'fullname'=>'Leonhard Euler', 'email'=>'president@whitehouse.gov', 'dob'=>'0000-00-00', 'language'=>'en-us', } class SRegTest < Minitest::Test def test_is11 assert_equal(NS_URI, NS_URI_1_1) end def test_check_field_name DATA_FIELDS.keys.each{|field_name| OpenID::check_sreg_field_name(field_name) } assert_raises(ArgumentError) { OpenID::check_sreg_field_name('invalid') } assert_raises(ArgumentError) { OpenID::check_sreg_field_name(nil) } end def test_unsupported endpoint = FakeEndpoint.new([]) assert(!OpenID::supports_sreg?(endpoint)) assert_equal([NS_URI_1_1,NS_URI_1_0], endpoint.checked_uris) end def test_supported_1_1 endpoint = FakeEndpoint.new([NS_URI_1_1]) assert(OpenID::supports_sreg?(endpoint)) assert_equal([NS_URI_1_1], endpoint.checked_uris) end def test_supported_1_0 endpoint = FakeEndpoint.new([NS_URI_1_0]) assert(OpenID::supports_sreg?(endpoint)) assert_equal([NS_URI_1_1,NS_URI_1_0], endpoint.checked_uris) end end class FakeEndpoint < Object attr_accessor :checked_uris def initialize(supported) @supported = supported @checked_uris = [] end def uses_extension(namespace_uri) @checked_uris << namespace_uri return @supported.member?(namespace_uri) end end class FakeMessage < Object attr_accessor :namespaces attr_accessor :openid1 def initialize @openid1 = false @namespaces = NamespaceMap.new end def is_openid1 return @openid1 end end class GetNSTest < Minitest::Test def setup @msg = FakeMessage.new end def test_openid2_empty ns_uri = OpenID::get_sreg_ns(@msg) assert_equal('sreg', @msg.namespaces.get_alias(ns_uri)) assert_equal(NS_URI, ns_uri) end def test_openid1_empty @msg.openid1 = true ns_uri = OpenID::get_sreg_ns(@msg) assert_equal('sreg', @msg.namespaces.get_alias(ns_uri)) assert_equal(NS_URI, ns_uri) end def test_openid1defined_1_0 @msg.openid1 = true @msg.namespaces.add(NS_URI_1_0) ns_uri = OpenID::get_sreg_ns(@msg) assert_equal(NS_URI_1_0, ns_uri) end def test_openid1_defined_1_0_override_alias [true, false].each{|openid_version| [NS_URI_1_0, NS_URI_1_1].each{|sreg_version| ['sreg', 'bogus'].each{|name| setup @msg.openid1 = openid_version @msg.namespaces.add_alias(sreg_version, name) ns_uri = OpenID::get_sreg_ns(@msg) assert_equal(name, @msg.namespaces.get_alias(ns_uri)) assert_equal(sreg_version, ns_uri) } } } end def test_openid1_defined_badly @msg.openid1 = true @msg.namespaces.add_alias('http://invalid/', 'sreg') assert_raises(NamespaceError) { OpenID::get_sreg_ns(@msg) } end def test_openid2_defined_badly @msg.namespaces.add_alias('http://invalid/', 'sreg') assert_raises(NamespaceError) { OpenID::get_sreg_ns(@msg) } end def test_openid2_defined_1_0 @msg.namespaces.add(NS_URI_1_0) ns_uri = OpenID::get_sreg_ns(@msg) assert_equal(NS_URI_1_0, ns_uri) end def test_openid1_sreg_ns_from_args args = { 'sreg.optional'=> 'nickname', 'sreg.required'=> 'dob', } m = Message.from_openid_args(args) assert_equal('nickname', m.get_arg(NS_URI_1_1, 'optional')) assert_equal('dob', m.get_arg(NS_URI_1_1, 'required')) end end class SRegRequestTest < Minitest::Test def test_construct_empty req = Request.new assert_equal([], req.optional) assert_equal([], req.required) assert_equal(nil, req.policy_url) assert_equal(NS_URI, req.ns_uri) end def test_construct_fields req = Request.new(['nickname'],['gender'],'http://policy', 'http://sreg.ns_uri') assert_equal(['gender'], req.optional) assert_equal(['nickname'], req.required) assert_equal('http://policy', req.policy_url) assert_equal('http://sreg.ns_uri', req.ns_uri) end def test_construct_bad_fields assert_raises(ArgumentError) {Request.new(['elvis'])} end def test_from_openid_request_message_copied message = Message.from_openid_args({"sreg.required" => "nickname"}) openid_req = Server::OpenIDRequest.new openid_req.message = message sreg_req = Request.from_openid_request(openid_req) # check that the message is copied by looking at sreg namespace assert_equal(NS_URI_1_1, message.namespaces.get_namespace_uri('sreg')) assert_equal(NS_URI, sreg_req.ns_uri) assert_equal(['nickname'], sreg_req.required) end def test_from_openid_request_ns_1_0 message = Message.from_openid_args({'ns.sreg' => NS_URI_1_0, "sreg.required" => "nickname"}) openid_req = Server::OpenIDRequest.new openid_req.message = message sreg_req = Request.from_openid_request(openid_req) assert_equal(NS_URI_1_0, sreg_req.ns_uri) assert_equal(['nickname'], sreg_req.required) end def test_from_openid_request_no_sreg message = Message.new openid_req = Server::OpenIDRequest.new openid_req.message = message sreg_req = Request.from_openid_request(openid_req) assert(sreg_req.nil?) end def test_parse_extension_args_empty req = Request.new req.parse_extension_args({}) end def test_parse_extension_args_extra_ignored req = Request.new req.parse_extension_args({'extra' => 'stuff'}) end def test_parse_extension_args_non_strict req = Request.new req.parse_extension_args({'required' => 'stuff'}) assert_equal([], req.required) end def test_parse_extension_args_strict req = Request.new assert_raises(ArgumentError) { req.parse_extension_args({'required' => 'stuff'}, true) } end def test_parse_extension_args_policy req = Request.new req.parse_extension_args({'policy_url' => 'http://policy'}, true) assert_equal('http://policy', req.policy_url) end def test_parse_extension_args_required_empty req = Request.new req.parse_extension_args({'required' => ''}, true) assert_equal([], req.required) end def test_parse_extension_args_optional_empty req = Request.new req.parse_extension_args({'optional' => ''},true) assert_equal([], req.optional) end def test_parse_extension_args_optional_single req = Request.new req.parse_extension_args({'optional' => 'nickname'},true) assert_equal(['nickname'], req.optional) end def test_parse_extension_args_optional_list req = Request.new req.parse_extension_args({'optional' => 'nickname,email'},true) assert_equal(['nickname','email'], req.optional) end def test_parse_extension_args_optional_list_bad_nonstrict req = Request.new req.parse_extension_args({'optional' => 'nickname,email,beer'}) assert_equal(['nickname','email'], req.optional) end def test_parse_extension_args_optional_list_bad_strict req = Request.new assert_raises(ArgumentError) { req.parse_extension_args({'optional' => 'nickname,email,beer'}, true) } end def test_parse_extension_args_both_nonstrict req = Request.new req.parse_extension_args({'optional' => 'nickname', 'required' => 'nickname'}) assert_equal(['nickname'], req.required) assert_equal([], req.optional) end def test_parse_extension_args_both_strict req = Request.new assert_raises(ArgumentError) { req.parse_extension_args({'optional' => 'nickname', 'required' => 'nickname'},true) } end def test_parse_extension_args_both_list req = Request.new req.parse_extension_args({'optional' => 'nickname,email', 'required' => 'country,postcode'},true) assert_equal(['nickname','email'], req.optional) assert_equal(['country','postcode'], req.required) end def test_all_requested_fields req = Request.new assert_equal([], req.all_requested_fields) req.request_field('nickname') assert_equal(['nickname'], req.all_requested_fields) req.request_field('gender', true) requested = req.all_requested_fields.sort assert_equal(['gender', 'nickname'], requested) end def test_were_fields_requested req = Request.new assert(!req.were_fields_requested?) req.request_field('nickname') assert(req.were_fields_requested?) end def test_member req = Request.new DATA_FIELDS.keys.each {|f| assert(!req.member?(f)) } assert(!req.member?('something else')) req.request_field('nickname') DATA_FIELDS.keys.each {|f| assert_equal(f == 'nickname',req.member?(f)) } end def test_request_field_bogus req = Request.new fields = DATA_FIELDS.keys fields.each {|f| req.request_field(f) } assert_equal(fields, req.optional) assert_equal([], req.required) # By default, adding the same fields over again has no effect fields.each {|f| req.request_field(f) } assert_equal(fields, req.optional) assert_equal([], req.required) # Requesting a field as required overrides requesting it as optional expected = fields[1..-1] overridden = fields[0] req.request_field(overridden, true) assert_equal(expected, req.optional) assert_equal([overridden], req.required) fields.each {|f| req.request_field(f, true) } assert_equal(fields, req.required) assert_equal([], req.optional) end def test_request_fields_type req = Request.new assert_raises(ArgumentError) { req.request_fields('nickname') } end def test_request_fields req = Request.new fields = DATA_FIELDS.keys req.request_fields(fields) assert_equal(fields, req.optional) assert_equal([], req.required) # By default, adding the same fields over again has no effect req.request_fields(fields) assert_equal(fields, req.optional) assert_equal([], req.required) # required overrides optional expected = fields[1..-1] overridden = fields[0] req.request_fields([overridden], true) assert_equal(expected, req.optional) assert_equal([overridden], req.required) req.request_fields(fields, true) assert_equal(fields, req.required) assert_equal([], req.optional) # optional does not override required req.request_fields(fields) assert_equal(fields, req.required) assert_equal([], req.optional) end def test_get_extension_args req = Request.new assert_equal({}, req.get_extension_args) req.request_field('nickname') assert_equal({'optional' => 'nickname'}, req.get_extension_args) req.request_field('email') assert_equal({'optional' => 'nickname,email'}, req.get_extension_args) req.request_field('gender', true) assert_equal({'optional' => 'nickname,email', 'required' => 'gender'}, req.get_extension_args) req.request_field('dob', true) assert_equal({'optional' => 'nickname,email', 'required' => 'gender,dob'}, req.get_extension_args) req.policy_url = 'http://policy' assert_equal({'optional' => 'nickname,email', 'required' => 'gender,dob', 'policy_url' => 'http://policy'}, req.get_extension_args) end end class DummySuccessResponse attr_accessor :message def initialize(message, signed_stuff) @message = message @signed_stuff = signed_stuff end def get_signed_ns(ns_uri) return @signed_stuff end end class SRegResponseTest < Minitest::Test def test_construct resp = Response.new(SOME_DATA) assert_equal(SOME_DATA, resp.get_extension_args) assert_equal(NS_URI, resp.ns_uri) resp2 = Response.new({}, "http://foo") assert_equal({}, resp2.get_extension_args) assert_equal('http://foo', resp2.ns_uri) end def test_from_success_response_signed message = Message.from_openid_args({ 'sreg.nickname'=>'The Mad Stork', }) success_resp = DummySuccessResponse.new(message, {}) sreg_resp = Response.from_success_response(success_resp) assert_equal({}, sreg_resp.get_extension_args) end def test_from_success_response_unsigned message = Message.from_openid_args({ 'ns.sreg' => NS_URI, 'sreg.nickname' => 'The Mad Stork', }) success_resp = DummySuccessResponse.new(message, {}) sreg_resp = Response.from_success_response(success_resp, false) assert_equal({'nickname' => 'The Mad Stork'}, sreg_resp.get_extension_args) end end class SendFieldsTest < Minitest::Test # class SendFieldsTest < Object def test_send_fields # create a request message with simple reg fields sreg_req = Request.new(['nickname', 'email'], ['fullname']) req_msg = Message.new req_msg.update_args(NS_URI, sreg_req.get_extension_args) req = Server::OpenIDRequest.new req.message = req_msg # -> checkid_* request # create a response resp_msg = Message.new resp = Server::OpenIDResponse.new(req) resp.fields = resp_msg sreg_resp = Response.extract_response(sreg_req, SOME_DATA) resp.add_extension(sreg_resp) # <- id_res response # extract sent fields sreg_data_resp = resp_msg.get_args(NS_URI) assert_equal({'nickname' => 'linusaur', 'email'=>'president@whitehouse.gov', 'fullname'=>'Leonhard Euler', }, sreg_data_resp) end end end end end ruby-openid-2.7.0debian.orig/test/test_fetchers.rb0000644000175000017500000003644412512544714021475 0ustar sbadiasbadia# encoding: utf-8 require 'minitest/autorun' require 'net/http' require 'webrick' require 'testutil' require 'util' require 'openid/fetchers' require 'stringio' begin require 'net/https' rescue LoadError # We need these names for testing. module OpenSSL module SSL class SSLError < StandardError; end end end end module HttpResultAssertions def assert_http_result_is(expected, result) assert_equal expected.code, result.code assert_equal expected.body, result.body assert_equal expected.final_url, result.final_url end end class BogusFetcher RESPONSE = "bogus" def fetch(url, body=nil, headers=nil, redirect_limit=5) return BogusFetcher::RESPONSE end end class FetcherTestCase < Minitest::Test include HttpResultAssertions include OpenID::TestUtil @@test_header_name = 'X-test-header' @@test_header_value = 'marmoset' class ExpectedResponse < Net::HTTPResponse attr_reader :final_url def initialize(code, final_url, body="the expected body", httpv="1.1", msg=nil) super(httpv, code, msg) @code = code @body = body @final_url = final_url end def body @body end end @@cases = [ # path, status code, expected url (nil = default to path) ['/success', 200, nil], ['/notfound', 404, nil], ['/badreq', 400, nil], ['/forbidden', 403, nil], ['/error', 500, nil], ['/server_error', 503, nil], ['/301redirect', 200, '/success'], ['/302redirect', 200, '/success'], ['/303redirect', 200, '/success'], ['/307redirect', 200, '/success'], ] def _redirect_with_code(code) lambda { |req, resp| resp.status = code resp['Location'] = _uri_build('/success') } end def _respond_with_code(code) lambda { |req, resp| resp.status = code resp.body = "the expected body" } end def _require_header lambda { |req, resp| assert_equal @@test_header_value, req[@@test_header_name] assert_match 'ruby-openid', req['User-agent'] } end def _require_post lambda { |req, resp| assert_equal 'POST', req.request_method assert_equal "postbody\n", req.body } end def _redirect_loop lambda { |req, resp| @_redirect_counter += 1 resp.status = 302 resp['Location'] = _uri_build('/redirect_loop') resp.body = "Fetched #{@_redirect_counter} times." assert @_redirect_counter < 10, "Fetched too many times." } end UTF8_PAGE_CONTENT = <<-EOHTML UTF-8 こんにちは EOHTML def _utf8_page lambda { |req, resp| resp['Content-Type'] = "text/html; charset=utf-8" body = UTF8_PAGE_CONTENT.dup resp.body = body } end def _unencoded_page lambda { |req, resp| resp['Content-Type'] = "text/html" body = "unencoded-body" resp.body = body } end def _badly_encoded_page lambda { |req, resp| resp['Content-Type'] = "text/html; charset=wtf" body = "badly-encoded-body" resp.body = body } end def setup if defined?(Encoding.default_external) @encoding_was = Encoding.default_external end @fetcher = OpenID::StandardFetcher.new @logfile = StringIO.new @weblog = WEBrick::Log.new(@logfile) @server = WEBrick::HTTPServer.new(:Port => 0, :Logger => @weblog, :AccessLog => []) @server_thread = Thread.new { @server.mount_proc('/success', _respond_with_code(200)) @server.mount_proc('/301redirect', _redirect_with_code(301)) @server.mount_proc('/302redirect', _redirect_with_code(302)) @server.mount_proc('/303redirect', _redirect_with_code(303)) @server.mount_proc('/307redirect', _redirect_with_code(307)) @server.mount_proc('/badreq', _respond_with_code(400)) @server.mount_proc('/forbidden', _respond_with_code(403)) @server.mount_proc('/notfound', _respond_with_code(404)) @server.mount_proc('/error', _respond_with_code(500)) @server.mount_proc('/server_error', _respond_with_code(503)) @server.mount_proc('/require_header', _require_header) @server.mount_proc('/redirect_to_reqheader') { |req, resp| resp.status = 302 resp['Location'] = _uri_build('/require_header') } @server.mount_proc('/post', _require_post) @server.mount_proc('/redirect_loop', _redirect_loop) @server.mount_proc('/utf8_page', _utf8_page) @server.mount_proc('/unencoded_page', _unencoded_page) @server.mount_proc('/badly_encoded_page', _badly_encoded_page) @server.start } @uri = _uri_build sleep 0.2 end def _uri_build(path='/') u = URI::HTTP.build({ :host => "localhost", :port => @server.config[:Port], :path => path, }) return u.to_s end def teardown if defined?(Encoding.default_external) Encoding.default_external = @encoding_was end @server.shutdown # Sleep a little because sometimes this blocks forever. @server_thread.join end =begin # XXX This test no longer works since we're not dealing with URI # objects internally. def test_final_url_tainted uri = _uri_build('/301redirect') result = @fetcher.fetch(uri) final_url = URI::parse(result.final_url) assert final_url.host.tainted? assert final_url.path.tainted? end =end def test_headers headers = { @@test_header_name => @@test_header_value } uri = _uri_build('/require_header') result = @fetcher.fetch(uri, nil, headers) # The real test runs under the WEBrick handler _require_header, # this just checks the return code from that. assert_equal '200', result.code, @logfile.string end def test_headers_after_redirect headers = { @@test_header_name => @@test_header_value } uri = _uri_build('/redirect_to_reqheader') result = @fetcher.fetch(uri, nil, headers) # The real test runs under the WEBrick handler _require_header, # this just checks the return code from that. assert_equal '200', result.code, @logfile.string end def test_post uri = _uri_build('/post') result = @fetcher.fetch(uri, "postbody\n") # The real test runs under the WEBrick handler _require_header, # this just checks the return code from that. assert_equal '200', result.code, @logfile.string end def test_redirect_limit @_redirect_counter = 0 uri = _uri_build('/redirect_loop') assert_raises(OpenID::HTTPRedirectLimitReached) { @fetcher.fetch(uri, body=nil, headers=nil, redirect_limit=0) } end def test_utf8_page uri = _uri_build('/utf8_page') response = @fetcher.fetch(uri) assert_equal(UTF8_PAGE_CONTENT, response.body) if response.body.respond_to?(:encoding) assert_equal(Encoding::UTF_8, response.body.encoding) end end def test_unencoded_page uri = _uri_build('/unencoded_page') response = @fetcher.fetch(uri) assert_equal("unencoded-body", response.body) # The actual encoding seems to depend on the server # setting in case it is not defined explicitely # if defined?(Encoding.default_external) # assert_equal(Encoding::UTF_8, response.body.encoding) # end end def test_badly_encoded_page if defined?(Encoding.default_external) Encoding.default_external = Encoding::SHIFT_JIS end uri = _uri_build('/badly_encoded_page') response = @fetcher.fetch(uri) assert_equal("badly-encoded-body", response.body) if defined?(Encoding.default_external) assert_equal(Encoding::SHIFT_JIS, response.body.encoding) end end def test_cases for path, expected_code, expected_url in @@cases uri = _uri_build(path) if expected_url.nil? expected_url = uri else expected_url = _uri_build(expected_url) end expected = ExpectedResponse.new(expected_code.to_s, expected_url) result = @fetcher.fetch(uri) begin assert_http_result_is expected, result rescue Minitest::Assertion => err if result.code == '500' && expected_code != 500 # Looks like our WEBrick harness broke. msg = < why assert_equal(why.to_s, "SSL support not found; cannot fetch https://someurl.com/") end end class FakeConnection < Net::HTTP attr_reader :use_ssl, :ca_file def initialize *args super @ca_file = nil end def use_ssl=(v) @use_ssl = v end def ca_file=(ca_file) @ca_file = ca_file end end def test_ssl_with_ca_file f = OpenID::StandardFetcher.new ca_file = "BOGUS" f.ca_file = ca_file f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_http) do |uri| FakeConnection.new(uri.host, uri.port) end testcase = self f.instance_def(:set_verified) do |conn, verified| testcase.assert(verified) end conn = f.make_connection(URI::parse("https://someurl.com")) assert_equal(conn.ca_file, ca_file) end def test_ssl_without_ca_file f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_http) do |uri| FakeConnection.new(uri.host, uri.port) end testcase = self f.instance_def(:set_verified) do |conn, verified| testcase.assert(!verified) end conn = nil assert_log_matches(/making https request to https:\/\/someurl.com without verifying/) { conn = f.make_connection(URI::parse("https://someurl.com")) } assert(conn.ca_file.nil?) end def test_make_http_nil f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_http) do |uri| nil end assert_raises(RuntimeError) { f.make_connection(URI::parse("http://example.com/")) } end def test_make_http_invalid f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_http) do |uri| "not a Net::HTTP object" end assert_raises(RuntimeError) { f.make_connection(URI::parse("http://example.com/")) } end class BrokenSSLConnection def start(&block) raise OpenSSL::SSL::SSLError end end def test_sslfetchingerror f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_connection) do |uri| BrokenSSLConnection.new end assert_raises(OpenID::SSLFetchingError) { f.fetch("https://bogus.com/") } end class TimeoutConnection def start(&block) raise Timeout::Error end end def test_fetchingerror f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_connection) do |uri| TimeoutConnection.new end assert_raises(OpenID::FetchingError) { f.fetch("https://bogus.com/") } end class TestingException < OpenID::FetchingError; end class NoSSLSupportConnection def supports_ssl? false end def start yield end def request_get(*args) raise TestingException end def post_connection_check(hostname) raise RuntimeError end def use_ssl? true end end class NoUseSSLConnection < NoSSLSupportConnection def use_ssl? false end end def test_post_connection_check_no_support_ssl f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_connection) do |uri| NoSSLSupportConnection.new end # post_connection_check should not be called. assert_raises(TestingException) { f.fetch("https://bogus.com/") } end def test_post_connection_check_no_use_ssl f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_connection) do |uri| NoUseSSLConnection.new end # post_connection_check should not be called. assert_raises(TestingException) { f.fetch("https://bogus.com/") } end class PostConnectionCheckException < OpenID::FetchingError; end class UseSSLConnection < NoSSLSupportConnection def use_ssl? true end def post_connection_check(hostname) raise PostConnectionCheckException end end def test_post_connection_check f = OpenID::StandardFetcher.new f.extend(OpenID::InstanceDefExtension) f.instance_def(:make_connection) do |uri| UseSSLConnection.new end f.instance_def(:supports_ssl?) do |conn| true end # post_connection_check should be called. assert_raises(PostConnectionCheckException) { f.fetch("https://bogus.com/") } end end class DefaultFetcherTest < Minitest::Test def setup OpenID.fetcher = nil end def test_default_fetcher assert(OpenID.fetcher.is_a?(OpenID::StandardFetcher)) # A custom fetcher can be set OpenID.fetcher = BogusFetcher.new # A test fetch should call the new fetcher assert(OpenID.fetch('not-a-url') == BogusFetcher::RESPONSE) # Set the fetcher to nil again OpenID.fetcher = nil assert(OpenID.fetcher.is_a?(OpenID::StandardFetcher)) end end class ProxyTest < Minitest::Test def test_proxy_unreachable begin f = OpenID::StandardFetcher.new('127.0.0.1', 1) # If this tries to connect to the proxy (on port 1), I expect # a 'connection refused' error. If it tries to contact the below # URI first, it will get some other sort of error. f.fetch("http://unittest.invalid") rescue OpenID::FetchingError => why # XXX: Is this a translatable string that is going to break? if why.message =~ /Connection refused/ return end raise why end flunk "expected Connection Refused, but it passed." end def test_proxy_env ENV['http_proxy'] = 'http://127.0.0.1:3128/' OpenID.fetcher_use_env_http_proxy # make_http just to give us something with readable attributes to inspect. conn = OpenID.fetcher.make_http(URI.parse('http://127.0.0.2')) assert_equal('127.0.0.1', conn.proxy_address) assert_equal(3128, conn.proxy_port) end # These aren't fully automated tests, but if you start a proxy # on port 8888 (tinyproxy's default) and check its logs... # def test_proxy # f = OpenID::StandardFetcher.new('127.0.0.1', 8888) # result = f.fetch("http://www.example.com/") # assert_match(/RFC.*2606/, result.body) # end # def test_proxy_https # f = OpenID::StandardFetcher.new('127.0.0.1', 8888) # result = f.fetch("https://www.myopenid.com/") # assert_match(/myOpenID/, result.body) # end end ruby-openid-2.7.0debian.orig/test/test_oauth.rb0000644000175000017500000001321112512544714020775 0ustar sbadiasbadiarequire 'minitest/autorun' require 'openid/extensions/oauth' require 'openid/message' require 'openid/server' require 'openid/consumer/responses' require 'openid/consumer/discovery' module OpenID module OAuthTest class OAuthRequestTestCase < Minitest::Test def setup @req = OAuth::Request.new end def test_construct assert_nil(@req.consumer) assert_nil(@req.scope) assert_equal('oauth', @req.ns_alias) req2 = OAuth::Request.new("CONSUMER","http://sample.com/some_scope") assert_equal("CONSUMER",req2.consumer) assert_equal("http://sample.com/some_scope",req2.scope) end def test_add_consumer @req.consumer="CONSUMER" assert_equal("CONSUMER",@req.consumer) end def test_add_scope @req.scope="http://sample.com/some_scope" assert_equal("http://sample.com/some_scope",@req.scope) end def test_get_extension_args assert_equal({}, @req.get_extension_args) @req.consumer="CONSUMER" assert_equal({'consumer' => 'CONSUMER'}, @req.get_extension_args) @req.scope="http://sample.com/some_scope" assert_equal({'consumer' => 'CONSUMER', 'scope' => 'http://sample.com/some_scope'}, @req.get_extension_args) end def test_parse_extension_args args = {'consumer' => 'CONSUMER', 'scope' => 'http://sample.com/some_scope'} @req.parse_extension_args(args) assert_equal("CONSUMER",@req.consumer) assert_equal("http://sample.com/some_scope",@req.scope) end def test_parse_extension_args_empty @req.parse_extension_args({}) assert_nil( @req.consumer ) assert_nil( @req.scope ) end def test_from_openid_request openid_req_msg = Message.from_openid_args({ 'mode' => 'checkid_setup', 'ns' => OPENID2_NS, 'ns.oauth' => OAuth::NS_URI, 'oauth.consumer' => 'CONSUMER', 'oauth.scope' => "http://sample.com/some_scope" }) oid_req = Server::OpenIDRequest.new oid_req.message = openid_req_msg req = OAuth::Request.from_openid_request(oid_req) assert_equal("CONSUMER",req.consumer) assert_equal("http://sample.com/some_scope",req.scope) end def test_from_openid_request_no_oauth message = Message.new openid_req = Server::OpenIDRequest.new openid_req.message = message oauth_req = OAuth::Request.from_openid_request(openid_req) assert(oauth_req.nil?) end end class DummySuccessResponse attr_accessor :message def initialize(message, signed_stuff) @message = message @signed_stuff = signed_stuff end def get_signed_ns(ns_uri) return @signed_stuff end end class OAuthResponseTestCase < Minitest::Test def setup @req = OAuth::Response.new end def test_construct assert_nil(@req.request_token) assert_nil(@req.scope) req2 = OAuth::Response.new("REQUESTTOKEN","http://sample.com/some_scope") assert_equal("REQUESTTOKEN",req2.request_token) assert_equal("http://sample.com/some_scope",req2.scope) end def test_add_request_token @req.request_token="REQUESTTOKEN" assert_equal("REQUESTTOKEN",@req.request_token) end def test_add_scope @req.scope="http://sample.com/some_scope" assert_equal("http://sample.com/some_scope",@req.scope) end def test_get_extension_args assert_equal({}, @req.get_extension_args) @req.request_token="REQUESTTOKEN" assert_equal({'request_token' => 'REQUESTTOKEN'}, @req.get_extension_args) @req.scope="http://sample.com/some_scope" assert_equal({'request_token' => 'REQUESTTOKEN', 'scope' => 'http://sample.com/some_scope'}, @req.get_extension_args) end def test_parse_extension_args args = {'request_token' => 'REQUESTTOKEN', 'scope' => 'http://sample.com/some_scope'} @req.parse_extension_args(args) assert_equal("REQUESTTOKEN",@req.request_token) assert_equal("http://sample.com/some_scope",@req.scope) end def test_parse_extension_args_empty @req.parse_extension_args({}) assert_nil( @req.request_token ) assert_nil( @req.scope ) end def test_from_success_response openid_req_msg = Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.oauth' => OAuth::NS_URI, 'ns.oauth' => OAuth::NS_URI, 'oauth.request_token' => 'REQUESTTOKEN', 'oauth.scope' => "http://sample.com/some_scope" }) signed_stuff = { 'request_token' => 'REQUESTTOKEN', 'scope' => "http://sample.com/some_scope" } oid_req = DummySuccessResponse.new(openid_req_msg, signed_stuff) req = OAuth::Response.from_success_response(oid_req) assert_equal("REQUESTTOKEN",req.request_token) assert_equal("http://sample.com/some_scope",req.scope) end def test_from_success_response_unsigned openid_req_msg = Message.from_openid_args({ 'mode' => 'id_res', 'ns' => OPENID2_NS, 'ns.oauth' => OAuth::NS_URI, 'oauth.request_token' => 'REQUESTTOKEN', 'oauth.scope' => "http://sample.com/some_scope" }) signed_stuff = {} endpoint = OpenIDServiceEndpoint.new oid_req = Consumer::SuccessResponse.new(endpoint, openid_req_msg, signed_stuff) req = OAuth::Response.from_success_response(oid_req) assert(req.nil?, req.inspect) end end end end ruby-openid-2.7.0debian.orig/test/discoverdata.rb0000644000175000017500000001003312512544714021265 0ustar sbadiasbadia require 'uri' require 'openid/yadis/constants' require 'openid/yadis/discovery' require 'openid/util' module OpenID module DiscoverData include TestDataMixin include Util TESTLIST = [ # success, input_name, id_name, result_name [true, "equiv", "equiv", "xrds"], [true, "header", "header", "xrds"], [true, "lowercase_header", "lowercase_header", "xrds"], [true, "xrds", "xrds", "xrds"], [true, "xrds_ctparam", "xrds_ctparam", "xrds_ctparam"], [true, "xrds_ctcase", "xrds_ctcase", "xrds_ctcase"], [false, "xrds_html", "xrds_html", "xrds_html"], [true, "redir_equiv", "equiv", "xrds"], [true, "redir_header", "header", "xrds"], [true, "redir_xrds", "xrds", "xrds"], [false, "redir_xrds_html", "xrds_html", "xrds_html"], [true, "redir_redir_equiv", "equiv", "xrds"], [false, "404_server_response", nil, nil], [false, "404_with_header", nil, nil], [false, "404_with_meta", nil, nil], [false, "201_server_response", nil, nil], [false, "500_server_response", nil, nil], ] @@example_xrds_file = 'example-xrds.xml' @@default_test_file = 'test1-discover.txt' @@discover_tests = {} def readTests(filename) data = read_data_file(filename, false) tests = {} data.split("\f\n", -1).each { |case_| name, content = case_.split("\n", 2) tests[name] = content } return tests end def getData(filename, name) if !@@discover_tests.member?(filename) @@discover_tests[filename] = readTests(filename) end file_tests = @@discover_tests[filename] return file_tests[name] end def fillTemplate(test_name, template, base_url, example_xrds) mapping = [ ['URL_BASE/', base_url], ['', example_xrds], ['YADIS_HEADER', Yadis::YADIS_HEADER_NAME], ['NAME', test_name], ] mapping.each { |k, v| template = template.gsub(/#{k}/, v) } return template end def generateSample(test_name, base_url, example_xrds=nil, filename=@@default_test_file) if example_xrds.nil? example_xrds = read_data_file(@@example_xrds_file, false) end begin template = getData(filename, test_name) rescue Errno::ENOENT raise ArgumentError(filename) end return fillTemplate(test_name, template, base_url, example_xrds) end def generateResult(base_url, input_name, id_name, result_name, success) uri = URI::parse(base_url) input_url = (uri + input_name).to_s # If the name is None then we expect the protocol to fail, which # we represent by None if id_name.nil? Util.assert(result_name.nil?) return input_url, DiscoveryFailure end result = generateSample(result_name, base_url) headers, content = result.split("\n\n", 2) header_lines = headers.split("\n") ctype = nil header_lines.each { |header_line| if header_line.start_with?('Content-Type:') _, ctype = header_line.split(':', 2) ctype = ctype.strip() break else ctype = nil end } id_url = (uri + id_name).to_s result = Yadis::DiscoveryResult.new(input_url) result.normalized_uri = id_url if success result.xrds_uri = (uri + result_name).to_s end result.content_type = ctype result.response_text = content return [input_url, result] end end end ruby-openid-2.7.0debian.orig/test/test_dh.rb0000644000175000017500000000466612512544714020266 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'openid/dh' module OpenID class DiffieHellmanExposed < OpenID::DiffieHellman def DiffieHellmanExposed.strxor_for_testing(a, b) return DiffieHellmanExposed.strxor(a, b) end end class DiffieHellmanTestCase < Minitest::Test include OpenID::TestDataMixin NUL = "\x00" def test_strxor_success [#input 1 input 2 expected [NUL, NUL, NUL ], ["\x01", NUL, "\x01" ], ["a", "a", NUL ], ["a", NUL, "a" ], ["abc", NUL * 3, "abc" ], ["x" * 10, NUL * 10, "x" * 10], ["\x01", "\x02", "\x03" ], ["\xf0", "\x0f", "\xff" ], ["\xff", "\x0f", "\xf0" ], ].each do |input1, input2, expected| actual = DiffieHellmanExposed.strxor_for_testing(input1, input2) assert_equal(expected.force_encoding("UTF-8"), actual.force_encoding("UTF-8")) end end def test_strxor_failure [ ['', 'a' ], ['foo', 'ba' ], [NUL * 3, NUL * 4], [255, 127 ].map{|h| (0..h).map{|i|i.chr}.join('')}, ].each do |aa, bb| assert_raises(ArgumentError) { DiffieHellmanExposed.strxor(aa, bb) } end end def test_simple_exchange dh1 = DiffieHellman.from_defaults() dh2 = DiffieHellman.from_defaults() secret1 = dh1.get_shared_secret(dh2.public) secret2 = dh2.get_shared_secret(dh1.public) assert_equal(secret1, secret2) end def test_xor_secret dh1 = DiffieHellman.from_defaults() dh2 = DiffieHellman.from_defaults() secret = "Shhhhhh! don't tell!" encrypted = dh1.xor_secret((CryptUtil.method :sha1), dh2.public, secret) decrypted = dh2.xor_secret((CryptUtil.method :sha1), dh1.public, encrypted) assert_equal(secret, decrypted) end def test_dh dh = DiffieHellman.from_defaults() class << dh def set_private_test(priv) set_private(priv) end end read_data_file('dh.txt', true).each do |line| priv, pub = line.split(' ').map {|x| x.to_i} dh.set_private_test(priv) assert_equal(dh.public, pub) end end def test_using_defaults dh = DiffieHellman.from_defaults() assert(dh.using_default_values?) dh = DiffieHellman.new(3, 2750161) assert(!dh.using_default_values?) end end end ruby-openid-2.7.0debian.orig/test/testutil.rb0000644000175000017500000000623312512544714020501 0ustar sbadiasbadiarequire "pathname" if defined? Minitest::Test # We're on Minitest 5+. Nothing to do here. else # Minitest 4 doesn't have Minitest::Test yet. Minitest::Test = MiniTest::Unit::TestCase end module OpenID module TestDataMixin TESTS_DIR = Pathname.new(__FILE__).dirname TEST_DATA_DIR = Pathname.new('data') def read_data_file(filename, lines=true, data_dir=TEST_DATA_DIR) fname = TESTS_DIR.join(data_dir, filename) if lines fname.readlines else fname.read end end end module FetcherMixin def with_fetcher(fetcher) original_fetcher = OpenID.fetcher begin OpenID.fetcher = fetcher return yield ensure OpenID.fetcher = original_fetcher end end end module Const def const(symbol, value) (class << self;self;end).instance_eval do define_method(symbol) { value } end end end class MockResponse attr_reader :code, :body def initialize(code, body) @code = code.to_s @body = body end end module ProtocolErrorMixin def assert_protocol_error(str_prefix) begin result = yield rescue ProtocolError => why message = "Expected prefix #{str_prefix.inspect}, got "\ "#{why.message.inspect}" assert(why.message.start_with?(str_prefix), message) else fail("Expected ProtocolError. Got #{result.inspect}") end end end module OverrideMethodMixin def with_method_overridden(method_name, proc) original = method(method_name) begin # TODO: find a combination of undef calls which prevent the warning verbose, $VERBOSE = $VERBOSE, false define_method(method_name, proc) module_function(method_name) $VERBOSE = verbose yield ensure if original.respond_to? :owner original.owner.send(:undef_method, method_name) original.owner.send :define_method, method_name, original else define_method(method_name, original) module_function(method_name) end end end end # To use: # > x = Object.new # > x.extend(InstanceDefExtension) # > x.instance_def(:monkeys) do # > "bananas" # > end # > x.monkeys # module InstanceDefExtension def instance_def(method_name, &proc) (class << self;self;end).instance_eval do # TODO: find a combination of undef calls which prevent the warning verbose, $VERBOSE = $VERBOSE, false define_method(method_name, proc) $VERBOSE = verbose end end end GOODSIG = '[A Good Signature]' class GoodAssoc attr_accessor :handle, :expires_in def initialize(handle='-blah-') @handle = handle @expires_in = 3600 end def check_message_signature(msg) msg.get_arg(OPENID_NS, 'sig') == GOODSIG end end class HTTPResponse def self._from_raw_data(status, body="", headers={}, final_url=nil) resp = Net::HTTPResponse.new('1.1', status.to_s, 'NONE') me = self._from_net_response(resp, final_url) me.initialize_http_header headers me.body = body return me end end end ruby-openid-2.7.0debian.orig/test/test_yadis_discovery.rb0000644000175000017500000001436712512544714023072 0ustar sbadiasbadiarequire 'minitest/autorun' require 'testutil' require 'uri' require 'openid/yadis/discovery' require 'openid/fetchers' require 'openid/util' require 'discoverdata' module OpenID module YadisDiscovery include FetcherMixin include DiscoverData STATUS_HEADER_RE = /Status: (\d+) .*?$/m def self.mkResponse(data) status_mo = data.scan(STATUS_HEADER_RE) headers_str, body = data.split("\n\n", 2) headers = {} headers_str.split("\n", -1).each { |line| k, v = line.split(':', 2) k = k.strip().downcase v = v.strip() headers[k] = v } status = status_mo[0][0].to_i return HTTPResponse._from_raw_data(status, body, headers) end class TestFetcher include DiscoverData def initialize(base_url) @base_url = base_url end def fetch(url, headers, body, redirect_limit=nil) current_url = url while true parsed = URI::parse(current_url) # parsed[2][1:] path = parsed.path[1..-1] begin data = generateSample(path, @base_url) rescue ArgumentError return HTTPResponse._from_raw_data(404, '', {}, current_url) end response = YadisDiscovery.mkResponse(data) if ["301", "302", "303", "307"].member?(response.code) current_url = response['location'] else response.final_url = current_url return response end end end end class MockFetcher def initialize @count = 0 end def fetch(uri, headers=nil, body=nil, redirect_limit=nil) @count += 1 if @count == 1 headers = { 'X-XRDS-Location'.downcase => 'http://unittest/404', } return HTTPResponse._from_raw_data(200, '', headers, uri) else return HTTPResponse._from_raw_data(404, '', {}, uri) end end end class TestSecondGet < Minitest::Test include FetcherMixin def test_404 uri = "http://something.unittest/" assert_raises(DiscoveryFailure) { with_fetcher(MockFetcher.new) { Yadis.discover(uri) } } end end class DiscoveryTestCase include DiscoverData include FetcherMixin def initialize(testcase, input_name, id_name, result_name, success) @base_url = 'http://invalid.unittest/' @testcase = testcase @input_name = input_name @id_name = id_name @result_name = result_name @success = success end def setup @input_url, @expected = generateResult(@base_url, @input_name, @id_name, @result_name, @success) end def do_discovery with_fetcher(TestFetcher.new(@base_url)) do Yadis.discover(@input_url) end end def runCustomTest setup if @expected.respond_to?("ancestors") and @expected.ancestors.member?(DiscoveryFailure) @testcase.assert_raises(DiscoveryFailure) { do_discovery } else result = do_discovery @testcase.assert_equal(@input_url, result.request_uri) msg = sprintf("Identity URL mismatch: actual = %s, expected = %s", result.normalized_uri, @expected.normalized_uri) @testcase.assert_equal(@expected.normalized_uri, result.normalized_uri, msg) msg = sprintf("Content mismatch: actual = %s, expected = %s", result.response_text, @expected.response_text) @testcase.assert_equal(@expected.response_text, result.response_text, msg) expected_keys = @expected.instance_variables expected_keys.sort! actual_keys = result.instance_variables actual_keys.sort! @testcase.assert_equal(actual_keys, expected_keys) @expected.instance_variables.each { |k| exp_v = @expected.instance_variable_get(k) act_v = result.instance_variable_get(k) @testcase.assert_equal(act_v, exp_v, [k, exp_v, act_v]) } end end end class NoContentTypeFetcher def fetch(url, body=nil, headers=nil, redirect_limit=nil) return OpenID::HTTPResponse._from_raw_data(200, "", {}, nil) end end class BlankContentTypeFetcher def fetch(url, body=nil, headers=nil, redirect_limit=nil) return OpenID::HTTPResponse._from_raw_data(200, "", {"Content-Type" => ""}, nil) end end class TestYadisDiscovery < Minitest::Test include FetcherMixin def test_yadis_discovery DiscoverData::TESTLIST.each { |success, input_name, id_name, result_name| test = DiscoveryTestCase.new(self, input_name, id_name, result_name, success) test.runCustomTest } end def test_is_xrds_yadis_location result = Yadis::DiscoveryResult.new('http://request.uri/') result.normalized_uri = "http://normalized/" result.xrds_uri = "http://normalized/xrds" assert(result.is_xrds) end def test_is_xrds_content_type result = Yadis::DiscoveryResult.new('http://request.uri/') result.normalized_uri = result.xrds_uri = "http://normalized/" result.content_type = Yadis::YADIS_CONTENT_TYPE assert(result.is_xrds) end def test_is_xrds_neither result = Yadis::DiscoveryResult.new('http://request.uri/') result.normalized_uri = result.xrds_uri = "http://normalized/" result.content_type = "another/content-type" assert(!result.is_xrds) end def test_no_content_type with_fetcher(NoContentTypeFetcher.new) do result = Yadis.discover("http://bogus") assert_equal(nil, result.content_type) end end def test_blank_content_type with_fetcher(BlankContentTypeFetcher.new) do result = Yadis.discover("http://bogus") assert_equal("", result.content_type) end end end end end ruby-openid-2.7.0debian.orig/test/test_message.rb0000644000175000017500000007426512512544714021321 0ustar sbadiasbadia# last synced with Python openid.test.test_message on 6/29/2007. require 'minitest/autorun' require 'util' require 'openid/message' require 'rexml/document' module OpenID module GetArgsMixin # Tests a standard set of behaviors of Message.get_arg with # variations on handling defaults. def get_arg_tests(ns, key, expected=nil) assert_equal(expected, @m.get_arg(ns, key)) if expected.nil? assert_equal(@m.get_arg(ns, key, :a_default), :a_default) assert_raises(Message::KeyNotFound) { @m.get_arg(ns, key, NO_DEFAULT) } else assert_equal(@m.get_arg(ns, key, :a_default), expected) assert_equal(@m.get_arg(ns, key, NO_DEFAULT), expected) end end end class EmptyMessageTestCase < Minitest::Test include GetArgsMixin def setup @m = Message.new end def test_get_aliased_arg_no_default assert_raises(Message::KeyNotFound) do @m.get_aliased_arg('ns.pork', NO_DEFAULT) end ns_uri = "urn:pork" @m.namespaces.add_alias(ns_uri, 'pork_alias') # Should return ns_uri. assert_equal(ns_uri, @m.get_aliased_arg('ns.pork_alias', NO_DEFAULT)) end def test_to_post_args assert_equal({}, @m.to_post_args) end def test_to_args assert_equal({}, @m.to_args) end def test_to_kvform assert_equal('', @m.to_kvform) end def test_from_kvform kvform = "foo:bar\none:two\n" args = {'foo' => 'bar', 'one' => 'two'} expected_result = Message.from_openid_args(args) assert_equal(expected_result, Message.from_kvform(kvform)) end def test_to_url_encoded assert_equal('', @m.to_url_encoded) end def test_to_url base_url = 'http://base.url/' assert_equal(base_url, @m.to_url(base_url)) end def test_get_openid assert_equal(nil, @m.get_openid_namespace) end def test_get_key_openid assert_raises(UndefinedOpenIDNamespace) { @m.get_key(OPENID_NS, nil) } end def test_get_key_bare assert_equal('foo', @m.get_key(BARE_NS, 'foo')) end def test_get_key_ns1 assert_equal(nil, @m.get_key(OPENID1_NS, 'foo')) end def test_get_key_ns2 assert_equal(nil, @m.get_key(OPENID2_NS, 'foo')) end def test_get_key_ns3 assert_equal(nil, @m.get_key('urn:something-special', 'foo')) end def test_has_key assert_raises(UndefinedOpenIDNamespace) { @m.has_key?(OPENID_NS, 'foo') } end def test_has_key_bare assert_equal(false, @m.has_key?(BARE_NS, 'foo')) end def test_has_key_ns1 assert_equal(false, @m.has_key?(OPENID1_NS, 'foo')) end def test_has_key_ns2 assert_equal(false, @m.has_key?(OPENID2_NS, 'foo')) end def test_has_key_ns3 assert_equal(false, @m.has_key?('urn:xxx', 'foo')) end def test_get_arg assert_raises(UndefinedOpenIDNamespace) { @m.get_args(OPENID_NS) } end def test_get_arg_bare get_arg_tests(BARE_NS, 'foo') end def test_get_arg_ns1 get_arg_tests(OPENID1_NS, 'foo') end def test_get_arg_ns2 get_arg_tests(OPENID2_NS, 'foo') end def test_get_arg_ns3 get_arg_tests('urn:nothing-significant', 'foo') end def test_get_args assert_raises(UndefinedOpenIDNamespace) { @m.get_args(OPENID_NS) } end def test_get_args_bare assert_equal({}, @m.get_args(BARE_NS)) end def test_get_args_ns1 assert_equal({}, @m.get_args(OPENID1_NS)) end def test_get_args_ns2 assert_equal({}, @m.get_args(OPENID2_NS)) end def test_get_args_ns3 assert_equal({}, @m.get_args('urn:xxx')) end def test_update_args assert_raises(UndefinedOpenIDNamespace) { @m.update_args(OPENID_NS, {'does not'=>'matter'}) } end def _test_update_args_ns(ns) updates = { 'camper van beethoven' => 'david l', 'magnolia electric, co' => 'jason m' } assert_equal({}, @m.get_args(ns)) @m.update_args(ns, updates) assert_equal(updates, @m.get_args(ns)) end def test_update_args_bare _test_update_args_ns(BARE_NS) end def test_update_args_ns1 _test_update_args_ns(OPENID1_NS) end def test_update_args_ns2 _test_update_args_ns(OPENID2_NS) end def test_update_args_ns3 _test_update_args_ns('urn:xxx') end def test_set_arg assert_raises(UndefinedOpenIDNamespace) { @m.set_arg(OPENID_NS,'does not','matter') } end def _test_set_arg_ns(ns) key = 'Camper Van Beethoven' value = 'David Lowery' assert_equal(nil, @m.get_arg(ns, key)) @m.set_arg(ns, key, value) assert_equal(value, @m.get_arg(ns, key)) end def test_set_arg_bare _test_set_arg_ns(BARE_NS) end def test_set_arg_ns1 _test_set_arg_ns(OPENID1_NS) end def test_set_arg_ns2 _test_set_arg_ns(OPENID2_NS) end def test_set_arg_ns3 _test_set_arg_ns('urn:xxx') end def test_del_arg assert_raises(UndefinedOpenIDNamespace) { @m.set_arg(OPENID_NS, 'does not', 'matter') } end def _test_del_arg_ns(ns) key = 'Fleeting Joys' assert_equal(nil, @m.del_arg(ns, key)) end def test_del_arg_bare _test_del_arg_ns(BARE_NS) end def test_del_arg_ns1 _test_del_arg_ns(OPENID1_NS) end def test_del_arg_ns2 _test_del_arg_ns(OPENID2_NS) end def test_del_arg_ns3 _test_del_arg_ns('urn:xxx') end def test_isOpenID1 assert_equal(false, @m.is_openid1) end def test_isOpenID2 assert_equal(false, @m.is_openid2) end def test_set_openid_namespace assert_raises(InvalidOpenIDNamespace) { @m.set_openid_namespace('http://invalid/', false) } end end class OpenID1MessageTest < Minitest::Test include GetArgsMixin def setup @m = Message.from_post_args({'openid.mode' => 'error', 'openid.error' => 'unit test'}) end def test_has_openid_ns assert_equal(OPENID1_NS, @m.get_openid_namespace) assert_equal(OPENID1_NS, @m.namespaces.get_namespace_uri(NULL_NAMESPACE)) end def test_get_aliased_arg assert_equal('error', @m.get_aliased_arg('mode')) end def test_get_aliased_arg_ns assert_equal(OPENID1_NS, @m.get_aliased_arg('ns')) end def test_get_aliased_arg_with_ns @m = Message.from_post_args( {'openid.mode' => 'error', 'openid.error' => 'unit test', 'openid.ns.invalid' => 'http://invalid/', 'openid.invalid.stuff' => 'things', 'openid.invalid.stuff.blinky' => 'powerplant', }) assert_equal('http://invalid/', @m.get_aliased_arg('ns.invalid')) assert_equal('things', @m.get_aliased_arg('invalid.stuff')) assert_equal('powerplant', @m.get_aliased_arg('invalid.stuff.blinky')) end def test_get_aliased_arg_with_ns_default @m = Message.from_post_args({}) assert_equal('monkeys!', @m.get_aliased_arg('ns.invalid', "monkeys!")) end def test_to_post_args assert_equal({'openid.mode' => 'error', 'openid.error' => 'unit test'}, @m.to_post_args) end def test_to_post_args_ns invalid_ns = 'http://invalid/' @m.namespaces.add_alias(invalid_ns, 'foos') @m.set_arg(invalid_ns, 'ball', 'awesome') @m.set_arg(BARE_NS, 'xey', 'value') assert_equal({'openid.mode' => 'error', 'openid.error' => 'unit test', 'openid.foos.ball' => 'awesome', 'xey' => 'value', 'openid.ns.foos' => 'http://invalid/' }, @m.to_post_args) end def test_to_args assert_equal({'mode' => 'error', 'error' => 'unit test'}, @m.to_args) end def test_to_kvform assert_equal("error:unit test\nmode:error\n", @m.to_kvform) end def test_to_url_encoded assert_equal('openid.error=unit+test&openid.mode=error', @m.to_url_encoded) end def test_to_url base_url = 'http://base.url/' actual = @m.to_url(base_url) actual_base = actual[0...base_url.length] assert_equal(base_url, actual_base) assert_equal('?', actual[base_url.length].chr) query = actual[base_url.length+1..-1] assert_equal({'openid.mode'=>['error'],'openid.error'=>['unit test']}, CGI.parse(query)) end def test_get_openid assert_equal(OPENID1_NS, @m.get_openid_namespace) end def test_get_key_openid assert_equal('openid.mode', @m.get_key(OPENID_NS, 'mode')) end def test_get_key_bare assert_equal('mode', @m.get_key(BARE_NS, 'mode')) end def test_get_key_ns1 assert_equal('openid.mode', @m.get_key(OPENID1_NS, 'mode')) end def test_get_key_ns2 assert_equal(nil, @m.get_key(OPENID2_NS, 'mode')) end def test_get_key_ns3 assert_equal(nil, @m.get_key('urn:xxx', 'mode')) end def test_has_key assert_equal(true, @m.has_key?(OPENID_NS, 'mode')) end def test_has_key_bare assert_equal(false, @m.has_key?(BARE_NS, 'mode')) end def test_has_key_ns1 assert_equal(true, @m.has_key?(OPENID1_NS, 'mode')) end def test_has_key_ns2 assert_equal(false, @m.has_key?(OPENID2_NS, 'mode')) end def test_has_key_ns3 assert_equal(false, @m.has_key?('urn:xxx', 'mode')) end def test_get_arg assert_equal('error', @m.get_arg(OPENID_NS, 'mode')) end def test_get_arg_bare get_arg_tests(BARE_NS, 'mode') end def test_get_arg_ns get_arg_tests(OPENID_NS, 'mode', 'error') end def test_get_arg_ns1 get_arg_tests(OPENID1_NS, 'mode', 'error') end def test_get_arg_ns2 get_arg_tests(OPENID2_NS, 'mode') end def test_get_arg_ns3 get_arg_tests('urn:nothing-significant', 'mode') end def test_get_args assert_equal({'mode'=>'error','error'=>'unit test'}, @m.get_args(OPENID_NS)) end def test_get_args_bare assert_equal({}, @m.get_args(BARE_NS)) end def test_get_args_ns1 assert_equal({'mode'=>'error','error'=>'unit test'}, @m.get_args(OPENID1_NS)) end def test_get_args_ns2 assert_equal({}, @m.get_args(OPENID2_NS)) end def test_get_args_ns3 assert_equal({}, @m.get_args('urn:xxx')) end def _test_update_args_ns(ns, before=nil) if before.nil? before = {} end update_args = { 'Camper van Beethoven'=>'David Lowery', 'Magnolia Electric Co.'=>'Jason Molina' } assert_equal(before, @m.get_args(ns)) @m.update_args(ns, update_args) after = before.dup after.update(update_args) assert_equal(after, @m.get_args(ns)) end def test_update_args _test_update_args_ns(OPENID_NS, {'mode'=>'error','error'=>'unit test'}) end def test_update_args_bare _test_update_args_ns(BARE_NS) end def test_update_args_ns1 _test_update_args_ns(OPENID1_NS, {'mode'=>'error','error'=>'unit test'}) end def test_update_args_ns2 _test_update_args_ns(OPENID2_NS) end def test_update_args_ns3 _test_update_args_ns('urn:xxx') end def _test_set_arg_ns(ns) key = 'awesometown' value = 'funny' assert_equal(nil, @m.get_arg(ns,key)) @m.set_arg(ns, key, value) assert_equal(value, @m.get_arg(ns,key)) end def test_set_arg; _test_set_arg_ns(OPENID_NS); end def test_set_arg_bare; _test_set_arg_ns(BARE_NS); end def test_set_arg_ns1; _test_set_arg_ns(OPENID1_NS); end def test_set_arg_ns2; _test_set_arg_ns(OPENID2_NS); end def test_set_arg_ns3; _test_set_arg_ns('urn:xxx'); end def _test_del_arg_ns(ns) key = 'marry an' value = 'ice cream sandwich' @m.set_arg(ns, key, value) assert_equal(value, @m.get_arg(ns,key)) @m.del_arg(ns,key) assert_equal(nil, @m.get_arg(ns,key)) end def test_del_arg; _test_del_arg_ns(OPENID_NS); end def test_del_arg_bare; _test_del_arg_ns(BARE_NS); end def test_del_arg_ns1; _test_del_arg_ns(OPENID1_NS); end def test_del_arg_ns2; _test_del_arg_ns(OPENID2_NS); end def test_del_arg_ns3; _test_del_arg_ns('urn:yyy'); end def test_isOpenID1 assert_equal(true, @m.is_openid1) end def test_isOpenID2 assert_equal(false, @m.is_openid2) end def test_equal assert_equal(Message.new, Message.new) refute_equal(Message.new, nil) end def test_from_openid_args_undefined_ns expected = 'almost.complete' msg = Message.from_openid_args({'coverage.is' => expected}) actual = msg.get_arg(OPENID1_NS, 'coverage.is') assert_equal(expected, actual) end # XXX: we need to implement the KVForm module before we can fix this def TODOtest_from_kvform kv = 'foos:ball\n' msg = Message.from_kvform(kv) assert_equal(msg.get(OPENID1_NS, 'foos'), 'ball') end def test_initialize_sets_namespace msg = Message.new(OPENID1_NS) assert_equal(OPENID1_NS, msg.get_openid_namespace) end end class OpenID1ExplicitMessageTest < Minitest::Test # XXX - check to make sure the test suite will get built the way this # expects. def setup @m = Message.from_post_args({'openid.mode'=>'error', 'openid.error'=>'unit test', 'openid.ns'=>OPENID1_NS}) end def test_to_post_args assert_equal({'openid.mode' => 'error', 'openid.error' => 'unit test', 'openid.ns'=>OPENID1_NS, }, @m.to_post_args) end def test_to_post_args_ns invalid_ns = 'http://invalid/' @m.namespaces.add_alias(invalid_ns, 'foos') @m.set_arg(invalid_ns, 'ball', 'awesome') @m.set_arg(BARE_NS, 'xey', 'value') assert_equal({'openid.mode' => 'error', 'openid.error' => 'unit test', 'openid.foos.ball' => 'awesome', 'xey' => 'value', 'openid.ns'=>OPENID1_NS, 'openid.ns.foos' => 'http://invalid/' }, @m.to_post_args) end def test_to_args assert_equal({'mode' => 'error', 'error' => 'unit test', 'ns'=>OPENID1_NS }, @m.to_args) end def test_to_kvform assert_equal("error:unit test\nmode:error\nns:#{OPENID1_NS}\n", @m.to_kvform) end def test_to_url_encoded assert_equal('openid.error=unit+test&openid.mode=error&openid.ns=http%3A%2F%2Fopenid.net%2Fsignon%2F1.0', @m.to_url_encoded) end def test_to_url base_url = 'http://base.url/' actual = @m.to_url(base_url) actual_base = actual[0...base_url.length] assert_equal(base_url, actual_base) assert_equal('?', actual[base_url.length].chr) query = actual[base_url.length+1..-1] assert_equal({'openid.mode'=>['error'], 'openid.error'=>['unit test'], 'openid.ns'=>[OPENID1_NS], }, CGI.parse(query)) end end class OpenID2MessageTest < Minitest::Test include TestUtil def setup @m = Message.from_post_args({'openid.mode'=>'error', 'openid.error'=>'unit test', 'openid.ns'=>OPENID2_NS}) @m.set_arg(BARE_NS, 'xey', 'value') end def test_to_args_fails assert_raises(ArgumentError) { @m.to_args } end def test_fix_ns_non_string # Using has_key to invoke _fix_ns since _fix_ns should be private assert_raises(ArgumentError) { @m.has_key?(:non_string_namespace, "key") } end def test_fix_ns_non_uri # Using has_key to invoke _fix_ns since _fix_ns should be private assert_log_matches(/identifiers SHOULD be URIs/) { @m.has_key?("foo", "key") } end def test_fix_ns_sreg_literal # Using has_key to invoke _fix_ns since _fix_ns should be private assert_log_matches(/identifiers SHOULD be URIs/, /instead of "sreg"/) { @m.has_key?("sreg", "key") } end def test_copy n = @m.copy assert_equal(@m, n) end def test_to_post_args assert_equal({'openid.mode' => 'error', 'openid.error' => 'unit test', 'openid.ns' => OPENID2_NS, 'xey' => 'value', }, @m.to_post_args) end def test_to_post_args_ns invalid_ns = 'http://invalid/' @m.namespaces.add_alias(invalid_ns, 'foos') @m.set_arg(invalid_ns, 'ball', 'awesome') assert_equal({'openid.mode' => 'error', 'openid.error' => 'unit test', 'openid.ns' => OPENID2_NS, 'openid.ns.foos' => invalid_ns, 'openid.foos.ball' => 'awesome', 'xey' => 'value', }, @m.to_post_args) end def test_to_args @m.del_arg(BARE_NS, 'xey') assert_equal({'mode' => 'error', 'error' => 'unit test', 'ns' => OPENID2_NS}, @m.to_args) end def test_to_kvform @m.del_arg(BARE_NS, 'xey') assert_equal("error:unit test\nmode:error\nns:#{OPENID2_NS}\n", @m.to_kvform) end def _test_urlencoded(s) expected_list = ["openid.error=unit+test", "openid.mode=error", "openid.ns=#{CGI.escape(OPENID2_NS)}", "xey=value"] # Hard to do this with string comparison since the mapping doesn't # preserve order. encoded_list = s.split('&') encoded_list.sort! assert_equal(expected_list, encoded_list) end def test_to_urlencoded _test_urlencoded(@m.to_url_encoded) end def test_to_url base_url = 'http://base.url/' actual = @m.to_url(base_url) actual_base = actual[0...base_url.length] assert_equal(base_url, actual_base) assert_equal('?', actual[base_url.length].chr) query = actual[base_url.length+1..-1] _test_urlencoded(query) end def test_get_openid assert_equal(OPENID2_NS, @m.get_openid_namespace) end def test_get_key_openid assert_equal('openid.mode', @m.get_key(OPENID2_NS, 'mode')) end def test_get_key_bare assert_equal('mode', @m.get_key(BARE_NS, 'mode')) end def test_get_key_ns1 assert_equal(nil, @m.get_key(OPENID1_NS, 'mode')) end def test_get_key_ns2 assert_equal('openid.mode', @m.get_key(OPENID2_NS, 'mode')) end def test_get_key_ns3 assert_equal(nil, @m.get_key('urn:xxx', 'mode')) end def test_has_key_openid assert_equal(true, @m.has_key?(OPENID_NS,'mode')) end def test_has_key_bare assert_equal(false, @m.has_key?(BARE_NS,'mode')) end def test_has_key_ns1 assert_equal(false, @m.has_key?(OPENID1_NS,'mode')) end def test_has_key_ns2 assert_equal(true, @m.has_key?(OPENID2_NS,'mode')) end def test_has_key_ns3 assert_equal(false, @m.has_key?('urn:xxx','mode')) end # XXX - getArgTest def test_get_arg_openid assert_equal('error', @m.get_arg(OPENID_NS,'mode')) end def test_get_arg_bare assert_equal(nil, @m.get_arg(BARE_NS,'mode')) end def test_get_arg_ns1 assert_equal(nil, @m.get_arg(OPENID1_NS,'mode')) end def test_get_arg_ns2 assert_equal('error', @m.get_arg(OPENID2_NS,'mode')) end def test_get_arg_ns3 assert_equal(nil, @m.get_arg('urn:bananastand','mode')) end def test_get_args_openid assert_equal({'mode'=>'error','error'=>'unit test'}, @m.get_args(OPENID_NS)) end def test_get_args_bare assert_equal({'xey'=>'value'}, @m.get_args(BARE_NS)) end def test_get_args_ns1 assert_equal({}, @m.get_args(OPENID1_NS)) end def test_get_args_ns2 assert_equal({'mode'=>'error','error'=>'unit test'}, @m.get_args(OPENID2_NS)) end def test_get_args_ns3 assert_equal({}, @m.get_args('urn:loose seal')) end def _test_update_args_ns(ns, before=nil) before = {} unless before update_args = {'aa'=>'bb','cc'=>'dd'} assert_equal(before, @m.get_args(ns)) @m.update_args(ns, update_args) after = before.dup after.update(update_args) assert_equal(after, @m.get_args(ns)) end def test_update_args_openid _test_update_args_ns(OPENID_NS, {'mode'=>'error','error'=>'unit test'}) end def test_update_args_bare _test_update_args_ns(BARE_NS, {'xey'=>'value'}) end def test_update_args_ns1 _test_update_args_ns(OPENID1_NS) end def test_update_args_ns2 _test_update_args_ns(OPENID2_NS, {'mode'=>'error','error'=>'unit test'}) end def test_update_args_ns3 _test_update_args_ns('urn:sven') end def _test_set_arg_ns(ns) key = "logan's" value = "run" assert_equal(nil, @m.get_arg(ns,key)) @m.set_arg(ns, key, value) assert_equal(value, @m.get_arg(ns,key)) end def test_set_arg_openid; _test_set_arg_ns(OPENID_NS); end def test_set_arg_bare; _test_set_arg_ns(BARE_NS); end def test_set_arg_ns1; _test_set_arg_ns(OPENID1_NS); end def test_set_arg_ns2; _test_set_arg_ns(OPENID2_NS); end def test_set_arg_ns3; _test_set_arg_ns('urn:g'); end def test_bad_alias # Make sure dotted aliases and OpenID protocol fields are not allowed # as namespace aliases. fields = OPENID_PROTOCOL_FIELDS + ['dotted.alias'] fields.each { |f| args = {"openid.ns.#{f}" => "blah#{f}", "openid.#{f}.foo" => "test#{f}"} # .fromPostArgs covers .fromPostArgs, .fromOpenIDArgs, # ._fromOpenIDArgs, and .fromOpenIDArgs (since it calls # .fromPostArgs). assert_raises(AssertionError) { Message.from_post_args(args) } } end def test_from_post_args msg = Message.from_post_args({'foos' => 'ball'}) assert_equal('ball', msg.get_arg(BARE_NS, 'foos')) end def _test_del_arg_ns(ns) key = 'no' value = 'socks' assert_equal(nil, @m.get_arg(ns, key)) @m.set_arg(ns, key, value) assert_equal(value, @m.get_arg(ns, key)) @m.del_arg(ns, key) assert_equal(nil, @m.get_arg(ns, key)) end def test_del_arg_openid; _test_del_arg_ns(OPENID_NS); end def test_del_arg_bare; _test_del_arg_ns(BARE_NS); end def test_del_arg_ns1; _test_del_arg_ns(OPENID1_NS); end def test_del_arg_ns2; _test_del_arg_ns(OPENID2_NS); end def test_del_arg_ns3; _test_del_arg_ns('urn:tofu'); end def test_overwrite_extension_arg ns = 'urn:unittest_extension' key = 'mykey' value_1 = 'value_1' value_2 = 'value_2' @m.set_arg(ns, key, value_1) assert_equal(value_1, @m.get_arg(ns, key)) @m.set_arg(ns, key, value_2) assert_equal(value_2, @m.get_arg(ns, key)) end def test_argList assert_raises(ArgumentError) { Message.from_post_args({'arg' => [1, 2, 3]}) } end def test_isOpenID1 assert_equal(false, @m.is_openid1) end def test_isOpenID2 assert_equal(true, @m.is_openid2) end end class MessageTest < Minitest::Test def setup @postargs = { 'openid.ns' => OPENID2_NS, 'openid.mode' => 'checkid_setup', 'openid.identity' => 'http://bogus.example.invalid:port/', 'openid.assoc_handle' => 'FLUB', 'openid.return_to' => 'Neverland', 'openid.ax.value.fullname' => "Bob&Smith'" } @action_url = 'scheme://host:port/path?query' @form_tag_attrs = { 'company' => 'janrain', 'class' => 'fancyCSS', } @submit_text = 'GO!' ### Expected data regardless of input @required_form_attrs = { 'accept-charset' => 'UTF-8', 'enctype' => 'application/x-www-form-urlencoded', 'method' => 'post', } end def _checkForm(html, message_, action_url, form_tag_attrs, submit_text) @xml = REXML::Document.new(html) # Get root element form = @xml.root # Check required form attributes @required_form_attrs.each { |k, v| assert(form.attributes[k] == v, "Expected '#{v}' for required form attribute '#{k}', got '#{form.attributes[k]}'") } # Check extra form attributes @form_tag_attrs.each { |k, v| # Skip attributes that already passed the required attribute # check, since they should be ignored by the form generation # code. if @required_form_attrs.include?(k) continue end assert(form.attributes[k] == v, "Form attribute '#{k}' should be '#{v}', found '#{form.attributes[k]}'") # Check hidden fields against post args hiddens = [] form.each { |e| if (e.is_a?(REXML::Element)) and (e.name.upcase() == 'INPUT') and (e.attributes['type'].upcase() == 'HIDDEN') # For each post arg, make sure there is a hidden with that # value. Make sure there are no other hiddens. hiddens += [e] end } message_.to_post_args().each { |name, value| success = false hiddens.each { |e| if e.attributes['name'] == name assert(e.attributes['value'] == value, "Expected value of hidden input '#{e.attributes['name']}' " + "to be '#{value}', got '#{e.attributes['value']}'") success = true break end } if !success flunk "Post arg '#{name}' not found in form" end } hiddens.each { |e| assert(message_.to_post_args().keys().include?(e.attributes['name']), "Form element for '#{e.attributes['name']}' not in " + "original message") } # Check action URL assert(form.attributes['action'] == action_url, "Expected form 'action' to be '#{action_url}', got '#{form.attributes['action']}'") # Check submit text submits = [] form.each { |e| if (e.is_a?(REXML::Element)) and (e.name.upcase() == 'INPUT') and e.attributes['type'].upcase() == 'SUBMIT' submits += [e] end } assert(submits.length == 1, "Expected only one 'input' with type = 'submit', got #{submits.length}") assert(submits[0].attributes['value'] == submit_text, "Expected submit value to be '#{submit_text}', " + "got '#{submits[0].attributes['value']}'") } end def test_toFormMarkup m = Message.from_post_args(@postargs) html = m.to_form_markup(@action_url, @form_tag_attrs, @submit_text) _checkForm(html, m, @action_url, @form_tag_attrs, @submit_text) end def test_overrideMethod # Be sure that caller cannot change form method to GET. m = Message.from_post_args(@postargs) tag_attrs = @form_tag_attrs.clone tag_attrs['method'] = 'GET' html = m.to_form_markup(@action_url, @form_tag_attrs, @submit_text) _checkForm(html, m, @action_url, @form_tag_attrs, @submit_text) end def test_overrideRequired # Be sure that caller CANNOT change the form charset for # encoding type. m = Message.from_post_args(@postargs) tag_attrs = @form_tag_attrs.clone tag_attrs['accept-charset'] = 'UCS4' tag_attrs['enctype'] = 'invalid/x-broken' html = m.to_form_markup(@action_url, tag_attrs, @submit_text) _checkForm(html, m, @action_url, tag_attrs, @submit_text) end end class NamespaceMapTestCase < Minitest::Test def test_onealias nsm = NamespaceMap.new uri = 'http://example.com/foo' _alias = 'foo' nsm.add_alias(uri, _alias) assert_equal(uri, nsm.get_namespace_uri(_alias)) assert_equal(_alias, nsm.get_alias(uri)) end def test_iteration nsm = NamespaceMap.new uripat = "http://example.com/foo%i" nsm.add(uripat % 0) (1..23).each { |i| assert_equal(false, nsm.member?(uripat % i)) nsm.add(uripat % i) } nsm.each { |uri, _alias| assert_equal(uri[22..-1], _alias[3..-1]) } nsm = NamespaceMap.new alias_ = 'bogus' uri = 'urn:bogus' nsm.add_alias(uri, alias_) assert_equal(nsm.aliases(), [alias_]) assert_equal(nsm.namespace_uris(), [uri]) end def test_register_default_alias invalid_ns = 'http://invalid/' alias_ = 'invalid' Message.register_namespace_alias(invalid_ns, alias_) # Doing it again doesn't raise an exception Message.register_namespace_alias(invalid_ns, alias_) # Once it's registered, you can't register it again assert_raises(NamespaceAliasRegistrationError) { Message.register_namespace_alias(invalid_ns, 'another_alias') } # Once it's registered, you can't register another URL with that alias assert_raises(NamespaceAliasRegistrationError) { Message.register_namespace_alias('http://janrain.com/', alias_) } # It gets used automatically by the Message class: msg = Message.from_openid_args({'invalid.stuff' => 'things'}) assert(msg.is_openid1) assert_equal(alias_, msg.namespaces.get_alias(invalid_ns)) assert_equal(invalid_ns, msg.namespaces.get_namespace_uri(alias_)) end def test_alias_defined_twice nsm = NamespaceMap.new uri = 'urn:bogus' nsm.add_alias(uri, 'foos') assert_raises(IndexError) { nsm.add_alias(uri, 'ball') } end end end ruby-openid-2.7.0debian.orig/test/test_kvpost.rb0000644000175000017500000000332612512544714021211 0ustar sbadiasbadiarequire "minitest/autorun" require "testutil" require "openid/kvpost" require "openid/kvform" require "openid/message" module OpenID class KVPostTestCase < Minitest::Test include FetcherMixin def mk_resp(status, resp_hash) return MockResponse.new(status, Util.dict_to_kv(resp_hash)) end def test_msg_from_http_resp_success resp = mk_resp(200, {'mode' => 'seitan'}) msg = Message.from_http_response(resp, 'http://invalid/') assert_equal({'openid.mode' => 'seitan'}, msg.to_post_args) end def test_400 args = {'error' => 'I ate too much cheese', 'error_code' => 'sadness'} resp = mk_resp(400, args) begin val = Message.from_http_response(resp, 'http://invalid/') rescue ServerError => why assert_equal(why.error_text, 'I ate too much cheese') assert_equal(why.error_code, 'sadness') assert_equal(why.message.to_args, args) else fail("Expected exception. Got: #{val}") end end def test_500 args = {'error' => 'I ate too much cheese', 'error_code' => 'sadness'} resp = mk_resp(500, args) assert_raises(HTTPStatusError) { Message.from_http_response(resp, 'http://invalid') } end def make_kv_post_with_response(status, args) resp = mk_resp(status, args) mock_fetcher = Class.new do define_method(:fetch) do |url, body, xxx, yyy| resp end end with_fetcher(mock_fetcher.new) do OpenID.make_kv_post(Message.from_openid_args(args), 'http://invalid/') end end def test_make_kv_post assert_raises(HTTPStatusError) { make_kv_post_with_response(500, {}) } end end end ruby-openid-2.7.0debian.orig/CHANGELOG.md0000644000175000017500000000656012512544714017134 0ustar sbadiasbadia# Changelog ## 2.7.0 * Use RFC 2396 compatible URI parser for trustroot - 7c84ec9ced3ccbdad575e02dbfa81e53b52f909e See https://github.com/openid/ruby-openid/pull/85 * Use HMAC from OpenSSL rather than Digest - ce2e30d7ff3308f17ef7d8c19d6f4752f76c9c40 See https://github.com/openid/ruby-openid/pull/84 * Check if OpenSSL is loaded - 751e55820d958ee781f5abb466a576d83ddde6fd ## 2.6.0 * More safely build filenames - 1c4a90630b183e7572b8ab5f2e3a3e0c0fecd2c7 See https://github.com/openid/ruby-openid/pull/80 * The session serializer of Rails4.1 is json - b44a1eb511dec3be25a07930121bc80cacec0f1c * Handle boolean value to fix signature issue - d65076269b77754da7db6e4b189edeeb9201600d See https://github.com/openid/ruby-openid/pull/76 ## 2.5.0 * Revert json serialization - 8dc60e553369df2300ebb4b83a29618aff643c2c See https://github.com/openid/ruby-openid/pull/73 ## 2.4.0 * Allow expecting a parameter to be nil during return_to verification - 708e992ab3e6c26d478283fc11faa6a0a74bfec0 * Serialize to objects that can be stored as json - db1d8f7b171a333dec4e861fe0fa53ac1d98b188 * Fixed missing XRDS HTTP header in sample provider - dc15fa07fd59fdcf46d659cce34c6ef7a6768fde ## 2.3.0 * Deprecated Ruby 1.8 support - 0694bebc83de0313cfef73a5d0ffd9a293ae71a0 * Fixed encoding errors in test suite - 7ac8e3978f9c733bd5ee8d6b742b515b5427ded2 * Be aware when using Hash or Array as default value for unknown Hash keys - #58 * Stop overwriting String#starts_with? and String#ends_with? if defined - #55 * Ignore Associations For OpenID2 (Google's Security Bug Fix) - #53 * Change "oauth" to "ui" in variable name in the UI extension - #52 * Eliminating runtime warnings - #50 #56 * Upgrade example Rails provider/consumer app to Rails 3 - #49 ## 2.2.3 * Fixed 'invalid byte sequence in UTF-8' error in parse_link_attrs - 0f46921a97677b83b106366c805063105c5e9f20 * Fixed license information in gemspec - f032e949e1ca9078ab7508d9629398ca2c36980a * Update starts/ends_with? to handle nil prefix - beee5e8d1dc24ad55725cfcc720eefba6bdbd279 ## 2.2.2 * Limit fetching file size & disable XML entity expansion - be2bab5c21f04735045e071411b349afb790078f Avoid DoS attack to RPs using large XRDS / too many XML entity expansion in XRDS. ## 2.2.1 * Make bundle exec rake work - 2100f281172427d1557ebe76afbd24072a22d04f * State license in gemspec for automated tools / rubygems.org page - 2d5c3cd8f2476b28d60609822120c79d71919b7b * Use default-external encoding instead of ascii for badly encoded pages - a68d2591ac350459c874da10108e6ff5a8c08750 * Colorize output and reveal tests that never ran - 4b0143f0a3b10060d5f52346954219bba3375039 ## 2.2.0 * Bundler compatibility and bundler gem tasks - 72d551945f9577bf5d0e516c673c648791b0e795 * register_namespace_alias for AX message - aeaf050d21aeb681a220758f1cc61b9086f73152 * Fixed JRuby (1.9 mode) incompatibilty - 40baed6cf7326025058a131c2b76047345618539 * Added UI extension support - a276a63d68639e985c1f327cf817489ccc5f9a17 * Add attr_reader for setup_url on SetupNeededResponse - 75a7e98005542ede6db3fc7f1fc551e0a2ca044a * Encode form inputs - c9e9b5b52f8a23df3159c2387b6330d5df40f35b * Fixed cleanup AR associations whose expiry is past, not upcoming - 2265179a6d5c8b51ccc741180db46b618dd3caf9 * Fixed issue with Memcache store and Dalli - ef84bf73da9c99c67b0632252bf0349e2360cbc7 * Improvements to ActiveRecordStore's gc rake task - 847e19bf60a6b8163c1e0d2e96dbd805c64e2880 ruby-openid-2.7.0debian.orig/lib/0000755000175000017500000000000012512544722016061 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/lib/openid/0000755000175000017500000000000012512544714017340 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/lib/openid/cryptutil.rb0000644000175000017500000000576712512544714021743 0ustar sbadiasbadiarequire "openid/util" require "digest/sha1" require "digest/sha2" begin require "openssl" rescue LoadError begin # Try loading the ruby-hmac files if they exist require "hmac-sha1" require "hmac-sha2" rescue LoadError # Nothing exists use included hmac files require "hmac/sha1" require "hmac/sha2" end end module OpenID # This module contains everything needed to perform low-level # cryptograph and data manipulation tasks. module CryptUtil # Generate a random number, doing a little extra work to make it # more likely that it's suitable for cryptography. If your system # doesn't have /dev/urandom then this number is not # cryptographically safe. See # # for more information. max is the largest possible value of such # a random number, where the result will be less than max. def CryptUtil.rand(max) Kernel.srand() return Kernel.rand(max) end def CryptUtil.sha1(text) return Digest::SHA1.digest(text) end def CryptUtil.hmac_sha1(key, text) if defined? OpenSSL OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, key, text) else return HMAC::SHA1.digest(key, text) end end def CryptUtil.sha256(text) return Digest::SHA256.digest(text) end def CryptUtil.hmac_sha256(key, text) if defined? OpenSSL OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, key, text) else return HMAC::SHA256.digest(key, text) end end # Generate a random string of the given length, composed of the # specified characters. If chars is nil, generate a string # composed of characters in the range 0..255. def CryptUtil.random_string(length, chars=nil) s = "" unless chars.nil? length.times { s << chars[rand(chars.length)] } else length.times { s << rand(256).chr } end return s end # Convert a number to its binary representation; return a string # of bytes. def CryptUtil.num_to_binary(n) bits = n.to_s(2) prepend = (8 - bits.length % 8) bits = ('0' * prepend) + bits return [bits].pack('B*') end # Convert a string of bytes into a number. def CryptUtil.binary_to_num(s) # taken from openid-ruby 0.0.1 s = "\000" * (4 - (s.length % 4)) + s num = 0 s.unpack('N*').each do |x| num <<= 32 num |= x end return num end # Encode a number as a base64-encoded byte string. def CryptUtil.num_to_base64(l) return OpenID::Util.to_base64(num_to_binary(l)) end # Decode a base64 byte string to a number. def CryptUtil.base64_to_num(s) return binary_to_num(OpenID::Util.from_base64(s)) end def CryptUtil.const_eq(s1, s2) if s1.length != s2.length return false end result = true s1.length.times do |i| result &= (s1[i] == s2[i]) end return result end end end ruby-openid-2.7.0debian.orig/lib/openid/association.rb0000644000175000017500000001655612512544714022216 0ustar sbadiasbadiarequire "openid/kvform" require "openid/util" require "openid/cryptutil" require "openid/message" module OpenID def self.get_secret_size(assoc_type) if assoc_type == 'HMAC-SHA1' return 20 elsif assoc_type == 'HMAC-SHA256' return 32 else raise ArgumentError("Unsupported association type: #{assoc_type}") end end # An Association holds the shared secret between a relying party and # an OpenID provider. class Association attr_reader :handle, :secret, :issued, :lifetime, :assoc_type FIELD_ORDER = [:version, :handle, :secret, :issued, :lifetime, :assoc_type,] # Load a serialized Association def self.deserialize(serialized) parsed = Util.kv_to_seq(serialized) parsed_fields = parsed.map{|k, v| k.to_sym} if parsed_fields != FIELD_ORDER raise ProtocolError, 'Unexpected fields in serialized association'\ " (Expected #{FIELD_ORDER.inspect}, got #{parsed_fields.inspect})" end version, handle, secret64, issued_s, lifetime_s, assoc_type = parsed.map {|field, value| value} if version != '2' raise ProtocolError, "Attempted to deserialize unsupported version "\ "(#{parsed[0][1].inspect})" end self.new(handle, Util.from_base64(secret64), Time.at(issued_s.to_i), lifetime_s.to_i, assoc_type) end # Create an Association with an issued time of now def self.from_expires_in(expires_in, handle, secret, assoc_type) issued = Time.now self.new(handle, secret, issued, expires_in, assoc_type) end def initialize(handle, secret, issued, lifetime, assoc_type) @handle = handle @secret = secret @issued = issued @lifetime = lifetime @assoc_type = assoc_type end # Serialize the association to a form that's consistent across # JanRain OpenID libraries. def serialize data = { :version => '2', :handle => handle, :secret => Util.to_base64(secret), :issued => issued.to_i.to_s, :lifetime => lifetime.to_i.to_s, :assoc_type => assoc_type, } Util.assert(data.length == FIELD_ORDER.length) pairs = FIELD_ORDER.map{|field| [field.to_s, data[field]]} return Util.seq_to_kv(pairs, true) end # The number of seconds until this association expires def expires_in(now=nil) if now.nil? now = Time.now.to_i else now = now.to_i end time_diff = (issued.to_i + lifetime) - now if time_diff < 0 return 0 else return time_diff end end # Generate a signature for a sequence of [key, value] pairs def sign(pairs) kv = Util.seq_to_kv(pairs) case assoc_type when 'HMAC-SHA1' CryptUtil.hmac_sha1(@secret, kv) when 'HMAC-SHA256' CryptUtil.hmac_sha256(@secret, kv) else raise ProtocolError, "Association has unknown type: "\ "#{assoc_type.inspect}" end end # Generate the list of pairs that form the signed elements of the # given message def make_pairs(message) signed = message.get_arg(OPENID_NS, 'signed') if signed.nil? raise ProtocolError, 'Missing signed list' end signed_fields = signed.split(',', -1) data = message.to_post_args signed_fields.map {|field| [field, data.fetch('openid.'+field,'')] } end # Return whether the message's signature passes def check_message_signature(message) message_sig = message.get_arg(OPENID_NS, 'sig') if message_sig.nil? raise ProtocolError, "#{message} has no sig." end calculated_sig = get_message_signature(message) return CryptUtil.const_eq(calculated_sig, message_sig) end # Get the signature for this message def get_message_signature(message) Util.to_base64(sign(make_pairs(message))) end def ==(other) (other.class == self.class and other.handle == self.handle and other.secret == self.secret and # The internals of the time objects seemed to differ # in an opaque way when serializing/unserializing. # I don't think this will be a problem. other.issued.to_i == self.issued.to_i and other.lifetime == self.lifetime and other.assoc_type == self.assoc_type) end # Add a signature (and a signed list) to a message. def sign_message(message) if (message.has_key?(OPENID_NS, 'sig') or message.has_key?(OPENID_NS, 'signed')) raise ArgumentError, 'Message already has signed list or signature' end extant_handle = message.get_arg(OPENID_NS, 'assoc_handle') if extant_handle and extant_handle != self.handle raise ArgumentError, "Message has a different association handle" end signed_message = message.copy() signed_message.set_arg(OPENID_NS, 'assoc_handle', self.handle) message_keys = signed_message.to_post_args.keys() signed_list = [] message_keys.each { |k| if k.start_with?('openid.') signed_list << k[7..-1] end } signed_list << 'signed' signed_list.sort! signed_message.set_arg(OPENID_NS, 'signed', signed_list.join(',')) sig = get_message_signature(signed_message) signed_message.set_arg(OPENID_NS, 'sig', sig) return signed_message end end class AssociationNegotiator attr_reader :allowed_types def self.get_session_types(assoc_type) case assoc_type when 'HMAC-SHA1' ['DH-SHA1', 'no-encryption'] when 'HMAC-SHA256' ['DH-SHA256', 'no-encryption'] else raise ProtocolError, "Unknown association type #{assoc_type.inspect}" end end def self.check_session_type(assoc_type, session_type) if !get_session_types(assoc_type).include?(session_type) raise ProtocolError, "Session type #{session_type.inspect} not "\ "valid for association type #{assoc_type.inspect}" end end def initialize(allowed_types) self.allowed_types=(allowed_types) end def copy Marshal.load(Marshal.dump(self)) end def allowed_types=(allowed_types) allowed_types.each do |assoc_type, session_type| self.class.check_session_type(assoc_type, session_type) end @allowed_types = allowed_types end def add_allowed_type(assoc_type, session_type=nil) if session_type.nil? session_types = self.class.get_session_types(assoc_type) else self.class.check_session_type(assoc_type, session_type) session_types = [session_type] end for session_type in session_types do @allowed_types << [assoc_type, session_type] end end def allowed?(assoc_type, session_type) @allowed_types.include?([assoc_type, session_type]) end def get_allowed_type @allowed_types.empty? ? nil : @allowed_types[0] end end DefaultNegotiator = AssociationNegotiator.new([['HMAC-SHA1', 'DH-SHA1'], ['HMAC-SHA1', 'no-encryption'], ['HMAC-SHA256', 'DH-SHA256'], ['HMAC-SHA256', 'no-encryption']]) EncryptedNegotiator = AssociationNegotiator.new([['HMAC-SHA1', 'DH-SHA1'], ['HMAC-SHA256', 'DH-SHA256']]) end ruby-openid-2.7.0debian.orig/lib/openid/consumer/0000755000175000017500000000000012512544714021173 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/lib/openid/consumer/idres.rb0000644000175000017500000004476012512544714022641 0ustar sbadiasbadiarequire "openid/message" require "openid/protocolerror" require "openid/kvpost" require "openid/consumer/discovery" require "openid/urinorm" module OpenID class TypeURIMismatch < ProtocolError attr_reader :type_uri, :endpoint def initialize(type_uri, endpoint) @type_uri = type_uri @endpoint = endpoint end end class Consumer @openid1_return_to_nonce_name = 'rp_nonce' @openid1_return_to_claimed_id_name = 'openid1_claimed_id' # Set the name of the query parameter that this library will use # to thread a nonce through an OpenID 1 transaction. It will be # appended to the return_to URL. def self.openid1_return_to_nonce_name=(query_arg_name) @openid1_return_to_nonce_name = query_arg_name end # See openid1_return_to_nonce_name= documentation def self.openid1_return_to_nonce_name @openid1_return_to_nonce_name end # Set the name of the query parameter that this library will use # to thread the requested URL through an OpenID 1 transaction (for # use when verifying discovered information). It will be appended # to the return_to URL. def self.openid1_return_to_claimed_id_name=(query_arg_name) @openid1_return_to_claimed_id_name = query_arg_name end # See openid1_return_to_claimed_id_name= def self.openid1_return_to_claimed_id_name @openid1_return_to_claimed_id_name end # Handles an openid.mode=id_res response. This object is # instantiated and used by the Consumer. class IdResHandler attr_reader :endpoint, :message def initialize(message, current_url, store=nil, endpoint=nil) @store = store # Fer the nonce and invalidate_handle @message = message @endpoint = endpoint @current_url = current_url @signed_list = nil # Start the verification process id_res end def signed_fields signed_list.map {|x| 'openid.' + x} end protected # This method will raise ProtocolError unless the request is a # valid id_res response. Once it has been verified, the methods # 'endpoint', 'message', and 'signed_fields' contain the # verified information. def id_res check_for_fields verify_return_to verify_discovery_results check_signature check_nonce end def server_url @endpoint.nil? ? nil : @endpoint.server_url end def openid_namespace @message.get_openid_namespace end def fetch(field, default=NO_DEFAULT) @message.get_arg(OPENID_NS, field, default) end def signed_list if @signed_list.nil? signed_list_str = fetch('signed', nil) if signed_list_str.nil? raise ProtocolError, 'Response missing signed list' end @signed_list = signed_list_str.split(',', -1) end @signed_list end def check_for_fields # XXX: if a field is missing, we should not have to explicitly # check that it's present, just make sure that the fields are # actually being used by the rest of the code in # tests. Although, which fields are signed does need to be # checked somewhere. basic_fields = ['return_to', 'assoc_handle', 'sig', 'signed'] basic_sig_fields = ['return_to', 'identity'] case openid_namespace when OPENID2_NS require_fields = basic_fields + ['op_endpoint'] require_sigs = basic_sig_fields + ['response_nonce', 'claimed_id', 'assoc_handle', 'op_endpoint'] when OPENID1_NS, OPENID11_NS require_fields = basic_fields + ['identity'] require_sigs = basic_sig_fields else raise RuntimeError, "check_for_fields doesn't know about "\ "namespace #{openid_namespace.inspect}" end require_fields.each do |field| if !@message.has_key?(OPENID_NS, field) raise ProtocolError, "Missing required field #{field}" end end require_sigs.each do |field| # Field is present and not in signed list if @message.has_key?(OPENID_NS, field) && !signed_list.member?(field) raise ProtocolError, "#{field.inspect} not signed" end end end def verify_return_to begin msg_return_to = URI.parse(URINorm::urinorm(fetch('return_to'))) rescue URI::InvalidURIError raise ProtocolError, ("return_to is not a valid URI") end verify_return_to_args(msg_return_to) if !@current_url.nil? verify_return_to_base(msg_return_to) end end def verify_return_to_args(msg_return_to) return_to_parsed_query = {} if !msg_return_to.query.nil? CGI.parse(msg_return_to.query).each_pair do |k, vs| return_to_parsed_query[k] = vs[0] end end query = @message.to_post_args return_to_parsed_query.each_pair do |rt_key, rt_val| msg_val = query[rt_key] if msg_val.nil? && !rt_val.nil? raise ProtocolError, "Message missing return_to argument '#{rt_key}'" elsif msg_val != rt_val raise ProtocolError, ("Parameter '#{rt_key}' value "\ "#{msg_val.inspect} does not match "\ "return_to's value #{rt_val.inspect}") end end @message.get_args(BARE_NS).each_pair do |bare_key, bare_val| rt_val = return_to_parsed_query[bare_key] if not return_to_parsed_query.has_key? bare_key # This may be caused by your web framework throwing extra # entries in to your parameters hash that were not GET or # POST parameters. For example, Rails has been known to # add "controller" and "action" keys; another server adds # at least a "format" key. raise ProtocolError, ("Unexpected parameter (not on return_to): "\ "'#{bare_key}'=#{rt_val.inspect})") end if rt_val != bare_val raise ProtocolError, ("Parameter '#{bare_key}' value "\ "#{bare_val.inspect} does not match "\ "return_to's value #{rt_val.inspect}") end end end def verify_return_to_base(msg_return_to) begin app_parsed = URI.parse(URINorm::urinorm(@current_url)) rescue URI::InvalidURIError raise ProtocolError, "current_url is not a valid URI: #{@current_url}" end [:scheme, :host, :port, :path].each do |meth| if msg_return_to.send(meth) != app_parsed.send(meth) raise ProtocolError, "return_to #{meth.to_s} does not match" end end end # Raises ProtocolError if the signature is bad def check_signature if @store.nil? assoc = nil else assoc = @store.get_association(server_url, fetch('assoc_handle')) end if assoc.nil? check_auth else if assoc.expires_in <= 0 # XXX: It might be a good idea sometimes to re-start the # authentication with a new association. Doing it # automatically opens the possibility for # denial-of-service by a server that just returns expired # associations (or really short-lived associations) raise ProtocolError, "Association with #{server_url} expired" elsif !assoc.check_message_signature(@message) raise ProtocolError, "Bad signature in response from #{server_url}" end end end def check_auth Util.log("Using 'check_authentication' with #{server_url}") begin request = create_check_auth_request rescue Message::KeyNotFound => why raise ProtocolError, "Could not generate 'check_authentication' "\ "request: #{why.message}" end response = OpenID.make_kv_post(request, server_url) process_check_auth_response(response) end def create_check_auth_request signed_list = @message.get_arg(OPENID_NS, 'signed', NO_DEFAULT).split(',') # check that we got all the signed arguments signed_list.each {|k| @message.get_aliased_arg(k, NO_DEFAULT) } ca_message = @message.copy ca_message.set_arg(OPENID_NS, 'mode', 'check_authentication') return ca_message end # Process the response message from a check_authentication # request, invalidating associations if requested. def process_check_auth_response(response) is_valid = response.get_arg(OPENID_NS, 'is_valid', 'false') invalidate_handle = response.get_arg(OPENID_NS, 'invalidate_handle') if !invalidate_handle.nil? Util.log("Received 'invalidate_handle' from server #{server_url}") if @store.nil? Util.log('Unexpectedly got "invalidate_handle" without a store!') else @store.remove_association(server_url, invalidate_handle) end end if is_valid != 'true' raise ProtocolError, ("Server #{server_url} responds that the "\ "'check_authentication' call is not valid") end end def check_nonce case openid_namespace when OPENID1_NS, OPENID11_NS nonce = @message.get_arg(BARE_NS, Consumer.openid1_return_to_nonce_name) # We generated the nonce, so it uses the empty string as the # server URL server_url = '' when OPENID2_NS nonce = @message.get_arg(OPENID2_NS, 'response_nonce') server_url = self.server_url else raise StandardError, 'Not reached' end if nonce.nil? raise ProtocolError, 'Nonce missing from response' end begin time, extra = Nonce.split_nonce(nonce) rescue ArgumentError raise ProtocolError, "Malformed nonce: #{nonce.inspect}" end if !@store.nil? && !@store.use_nonce(server_url, time, extra) raise ProtocolError, ("Nonce already used or out of range: "\ "#{nonce.inspect}") end end def verify_discovery_results begin case openid_namespace when OPENID1_NS, OPENID11_NS verify_discovery_results_openid1 when OPENID2_NS verify_discovery_results_openid2 else raise StandardError, "Not reached: #{openid_namespace}" end rescue Message::KeyNotFound => why raise ProtocolError, "Missing required field: #{why.message}" end end def verify_discovery_results_openid2 to_match = OpenIDServiceEndpoint.new to_match.type_uris = [OPENID_2_0_TYPE] to_match.claimed_id = fetch('claimed_id', nil) to_match.local_id = fetch('identity', nil) to_match.server_url = fetch('op_endpoint') if to_match.claimed_id.nil? && !to_match.local_id.nil? raise ProtocolError, ('openid.identity is present without '\ 'openid.claimed_id') elsif !to_match.claimed_id.nil? && to_match.local_id.nil? raise ProtocolError, ('openid.claimed_id is present without '\ 'openid.identity') # This is a response without identifiers, so there's really no # checking that we can do, so return an endpoint that's for # the specified `openid.op_endpoint' elsif to_match.claimed_id.nil? @endpoint = OpenIDServiceEndpoint.from_op_endpoint_url(to_match.server_url) return end if @endpoint.nil? Util.log('No pre-discovered information supplied') discover_and_verify(to_match.claimed_id, [to_match]) else begin verify_discovery_single(@endpoint, to_match) rescue ProtocolError => why Util.log("Error attempting to use stored discovery "\ "information: #{why.message}") Util.log("Attempting discovery to verify endpoint") discover_and_verify(to_match.claimed_id, [to_match]) end end if @endpoint.claimed_id != to_match.claimed_id @endpoint = @endpoint.dup @endpoint.claimed_id = to_match.claimed_id end end def verify_discovery_results_openid1 claimed_id = @message.get_arg(BARE_NS, Consumer.openid1_return_to_claimed_id_name) if claimed_id.nil? if @endpoint.nil? raise ProtocolError, ("When using OpenID 1, the claimed ID must "\ "be supplied, either by passing it through "\ "as a return_to parameter or by using a "\ "session, and supplied to the IdResHandler "\ "when it is constructed.") else claimed_id = @endpoint.claimed_id end end to_match = OpenIDServiceEndpoint.new to_match.type_uris = [OPENID_1_1_TYPE] to_match.local_id = fetch('identity') # Restore delegate information from the initiation phase to_match.claimed_id = claimed_id to_match_1_0 = to_match.dup to_match_1_0.type_uris = [OPENID_1_0_TYPE] if !@endpoint.nil? begin begin verify_discovery_single(@endpoint, to_match) rescue TypeURIMismatch verify_discovery_single(@endpoint, to_match_1_0) end rescue ProtocolError => why Util.log('Error attempting to use stored discovery information: ' + why.message) Util.log('Attempting discovery to verify endpoint') else return @endpoint end end # Either no endpoint was supplied or OpenID 1.x verification # of the information that's in the message failed on that # endpoint. discover_and_verify(to_match.claimed_id, [to_match, to_match_1_0]) end # Given an endpoint object created from the information in an # OpenID response, perform discovery and verify the discovery # results, returning the matching endpoint that is the result of # doing that discovery. def discover_and_verify(claimed_id, to_match_endpoints) Util.log("Performing discovery on #{claimed_id}") _, services = OpenID.discover(claimed_id) if services.length == 0 # XXX: this might want to be something other than # ProtocolError. In Python, it's DiscoveryFailure raise ProtocolError, ("No OpenID information found at "\ "#{claimed_id}") end verify_discovered_services(claimed_id, services, to_match_endpoints) end def verify_discovered_services(claimed_id, services, to_match_endpoints) # Search the services resulting from discovery to find one # that matches the information from the assertion failure_messages = [] for endpoint in services for to_match_endpoint in to_match_endpoints begin verify_discovery_single(endpoint, to_match_endpoint) rescue ProtocolError => why failure_messages << why.message else # It matches, so discover verification has # succeeded. Return this endpoint. @endpoint = endpoint return end end end Util.log("Discovery verification failure for #{claimed_id}") failure_messages.each do |failure_message| Util.log(" * Endpoint mismatch: " + failure_message) end # XXX: is DiscoveryFailure in Python OpenID raise ProtocolError, ("No matching endpoint found after "\ "discovering #{claimed_id}") end def verify_discovery_single(endpoint, to_match) # Every type URI that's in the to_match endpoint has to be # present in the discovered endpoint. for type_uri in to_match.type_uris if !endpoint.uses_extension(type_uri) raise TypeURIMismatch.new(type_uri, endpoint) end end # Fragments do not influence discovery, so we can't compare a # claimed identifier with a fragment to discovered information. defragged_claimed_id = case Yadis::XRI.identifier_scheme(to_match.claimed_id) when :xri to_match.claimed_id when :uri begin parsed = URI.parse(to_match.claimed_id) rescue URI::InvalidURIError to_match.claimed_id else parsed.fragment = nil parsed.to_s end else raise StandardError, 'Not reached' end if defragged_claimed_id != endpoint.claimed_id raise ProtocolError, ("Claimed ID does not match (different "\ "subjects!), Expected "\ "#{defragged_claimed_id}, got "\ "#{endpoint.claimed_id}") end if to_match.get_local_id != endpoint.get_local_id raise ProtocolError, ("local_id mismatch. Expected "\ "#{to_match.get_local_id}, got "\ "#{endpoint.get_local_id}") end # If the server URL is nil, this must be an OpenID 1 # response, because op_endpoint is a required parameter in # OpenID 2. In that case, we don't actually care what the # discovered server_url is, because signature checking or # check_auth should take care of that check for us. if to_match.server_url.nil? if to_match.preferred_namespace != OPENID1_NS raise StandardError, "The code calling this must ensure that OpenID 2 "\ "responses have a non-none `openid.op_endpoint' and "\ "that it is set as the `server_url' attribute of the "\ "`to_match' endpoint." end elsif to_match.server_url != endpoint.server_url raise ProtocolError, ("OP Endpoint mismatch. Expected"\ "#{to_match.server_url}, got "\ "#{endpoint.server_url}") end end end end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/associationmanager.rb0000644000175000017500000003142212512544714025371 0ustar sbadiasbadiarequire "openid/dh" require "openid/util" require "openid/kvpost" require "openid/cryptutil" require "openid/protocolerror" require "openid/association" module OpenID class Consumer # A superclass for implementing Diffie-Hellman association sessions. class DiffieHellmanSession class << self attr_reader :session_type, :secret_size, :allowed_assoc_types, :hashfunc end def initialize(dh=nil) if dh.nil? dh = DiffieHellman.from_defaults end @dh = dh end # Return the query parameters for requesting an association # using this Diffie-Hellman association session def get_request args = {'dh_consumer_public' => CryptUtil.num_to_base64(@dh.public)} if (!@dh.using_default_values?) args['dh_modulus'] = CryptUtil.num_to_base64(@dh.modulus) args['dh_gen'] = CryptUtil.num_to_base64(@dh.generator) end return args end # Process the response from a successful association request and # return the shared secret for this association def extract_secret(response) dh_server_public64 = response.get_arg(OPENID_NS, 'dh_server_public', NO_DEFAULT) enc_mac_key64 = response.get_arg(OPENID_NS, 'enc_mac_key', NO_DEFAULT) dh_server_public = CryptUtil.base64_to_num(dh_server_public64) enc_mac_key = Util.from_base64(enc_mac_key64) return @dh.xor_secret(self.class.hashfunc, dh_server_public, enc_mac_key) end end # A Diffie-Hellman association session that uses SHA1 as its hash # function class DiffieHellmanSHA1Session < DiffieHellmanSession @session_type = 'DH-SHA1' @secret_size = 20 @allowed_assoc_types = ['HMAC-SHA1'] @hashfunc = CryptUtil.method(:sha1) end # A Diffie-Hellman association session that uses SHA256 as its hash # function class DiffieHellmanSHA256Session < DiffieHellmanSession @session_type = 'DH-SHA256' @secret_size = 32 @allowed_assoc_types = ['HMAC-SHA256'] @hashfunc = CryptUtil.method(:sha256) end # An association session that does not use encryption class NoEncryptionSession class << self attr_reader :session_type, :allowed_assoc_types end @session_type = 'no-encryption' @allowed_assoc_types = ['HMAC-SHA1', 'HMAC-SHA256'] def get_request return {} end def extract_secret(response) mac_key64 = response.get_arg(OPENID_NS, 'mac_key', NO_DEFAULT) return Util.from_base64(mac_key64) end end # An object that manages creating and storing associations for an # OpenID provider endpoint class AssociationManager def self.create_session(session_type) case session_type when 'no-encryption' NoEncryptionSession.new when 'DH-SHA1' DiffieHellmanSHA1Session.new when 'DH-SHA256' DiffieHellmanSHA256Session.new else raise ArgumentError, "Unknown association session type: "\ "#{session_type.inspect}" end end def initialize(store, server_url, compatibility_mode=false, negotiator=nil) @store = store @server_url = server_url @compatibility_mode = compatibility_mode @negotiator = negotiator || DefaultNegotiator end def get_association if @store.nil? return nil end assoc = @store.get_association(@server_url) if assoc.nil? || assoc.expires_in <= 0 assoc = negotiate_association if !assoc.nil? @store.store_association(@server_url, assoc) end end return assoc end def negotiate_association assoc_type, session_type = @negotiator.get_allowed_type begin return request_association(assoc_type, session_type) rescue ServerError => why supported_types = extract_supported_association_type(why, assoc_type) if !supported_types.nil? # Attempt to create an association from the assoc_type and # session_type that the server told us it supported. assoc_type, session_type = supported_types begin return request_association(assoc_type, session_type) rescue ServerError => why Util.log("Server #{@server_url} refused its suggested " \ "association type: session_type=#{session_type}, " \ "assoc_type=#{assoc_type}") return nil end end rescue InvalidOpenIDNamespace Util.log("Server #{@server_url} returned a malformed association " \ "response. Falling back to check_id mode for this request.") return nil end end protected def extract_supported_association_type(server_error, assoc_type) # Any error message whose code is not 'unsupported-type' should # be considered a total failure. if (server_error.error_code != 'unsupported-type' or server_error.message.is_openid1) Util.log("Server error when requesting an association from "\ "#{@server_url}: #{server_error.error_text}") return nil end # The server didn't like the association/session type that we # sent, and it sent us back a message that might tell us how to # handle it. Util.log("Unsupported association type #{assoc_type}: "\ "#{server_error.error_text}") # Extract the session_type and assoc_type from the error message assoc_type = server_error.message.get_arg(OPENID_NS, 'assoc_type') session_type = server_error.message.get_arg(OPENID_NS, 'session_type') if assoc_type.nil? or session_type.nil? Util.log("Server #{@server_url} responded with unsupported "\ "association session but did not supply a fallback.") return nil elsif !@negotiator.allowed?(assoc_type, session_type) Util.log("Server sent unsupported session/association type: "\ "session_type=#{session_type}, assoc_type=#{assoc_type}") return nil else return [assoc_type, session_type] end end # Make and process one association request to this endpoint's OP # endpoint URL. Returns an association object or nil if the # association processing failed. Raises ServerError when the # remote OpenID server returns an error. def request_association(assoc_type, session_type) assoc_session, args = create_associate_request(assoc_type, session_type) begin response = OpenID.make_kv_post(args, @server_url) return extract_association(response, assoc_session) rescue HTTPStatusError => why Util.log("Got HTTP status error when requesting association: #{why}") return nil rescue Message::KeyNotFound => why Util.log("Missing required parameter in response from "\ "#{@server_url}: #{why}") return nil rescue ProtocolError => why Util.log("Protocol error processing response from #{@server_url}: "\ "#{why}") return nil end end # Create an association request for the given assoc_type and # session_type. Returns a pair of the association session object # and the request message that will be sent to the server. def create_associate_request(assoc_type, session_type) assoc_session = self.class.create_session(session_type) args = { 'mode' => 'associate', 'assoc_type' => assoc_type, } if !@compatibility_mode args['ns'] = OPENID2_NS end # Leave out the session type if we're in compatibility mode # *and* it's no-encryption. if !@compatibility_mode || assoc_session.class.session_type != 'no-encryption' args['session_type'] = assoc_session.class.session_type end args.merge!(assoc_session.get_request) message = Message.from_openid_args(args) return assoc_session, message end # Given an association response message, extract the OpenID 1.X # session type. Returns the association type for this message # # This function mostly takes care of the 'no-encryption' default # behavior in OpenID 1. # # If the association type is plain-text, this function will # return 'no-encryption' def get_openid1_session_type(assoc_response) # If it's an OpenID 1 message, allow session_type to default # to nil (which signifies "no-encryption") session_type = assoc_response.get_arg(OPENID_NS, 'session_type') # Handle the differences between no-encryption association # respones in OpenID 1 and 2: # no-encryption is not really a valid session type for # OpenID 1, but we'll accept it anyway, while issuing a # warning. if session_type == 'no-encryption' Util.log("WARNING: #{@server_url} sent 'no-encryption'"\ "for OpenID 1.X") # Missing or empty session type is the way to flag a # 'no-encryption' response. Change the session type to # 'no-encryption' so that it can be handled in the same # way as OpenID 2 'no-encryption' respones. elsif session_type == '' || session_type.nil? session_type = 'no-encryption' end return session_type end def self.extract_expires_in(message) # expires_in should be a base-10 string. expires_in_str = message.get_arg(OPENID_NS, 'expires_in', NO_DEFAULT) if !(/\A\d+\Z/ =~ expires_in_str) raise ProtocolError, "Invalid expires_in field: #{expires_in_str}" end expires_in_str.to_i end # Attempt to extract an association from the response, given the # association response message and the established association # session. def extract_association(assoc_response, assoc_session) # Extract the common fields from the response, raising an # exception if they are not found assoc_type = assoc_response.get_arg(OPENID_NS, 'assoc_type', NO_DEFAULT) assoc_handle = assoc_response.get_arg(OPENID_NS, 'assoc_handle', NO_DEFAULT) expires_in = self.class.extract_expires_in(assoc_response) # OpenID 1 has funny association session behaviour. if assoc_response.is_openid1 session_type = get_openid1_session_type(assoc_response) else session_type = assoc_response.get_arg(OPENID2_NS, 'session_type', NO_DEFAULT) end # Session type mismatch if assoc_session.class.session_type != session_type if (assoc_response.is_openid1 and session_type == 'no-encryption') # In OpenID 1, any association request can result in a # 'no-encryption' association response. Setting # assoc_session to a new no-encryption session should # make the rest of this function work properly for # that case. assoc_session = NoEncryptionSession.new else # Any other mismatch, regardless of protocol version # results in the failure of the association session # altogether. raise ProtocolError, "Session type mismatch. Expected "\ "#{assoc_session.class.session_type}, got "\ "#{session_type}" end end # Make sure assoc_type is valid for session_type if !assoc_session.class.allowed_assoc_types.member?(assoc_type) raise ProtocolError, "Unsupported assoc_type for session "\ "#{assoc_session.class.session_type} "\ "returned: #{assoc_type}" end # Delegate to the association session to extract the secret # from the response, however is appropriate for that session # type. begin secret = assoc_session.extract_secret(assoc_response) rescue Message::KeyNotFound, ArgumentError => why raise ProtocolError, "Malformed response for "\ "#{assoc_session.class.session_type} "\ "session: #{why.message}" end return Association.from_expires_in(expires_in, assoc_handle, secret, assoc_type) end end end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/discovery.rb0000644000175000017500000003700212512544714023531 0ustar sbadiasbadia# Functions to discover OpenID endpoints from identifiers. require 'uri' require 'openid/util' require 'openid/fetchers' require 'openid/urinorm' require 'openid/message' require 'openid/yadis/discovery' require 'openid/yadis/xrds' require 'openid/yadis/xri' require 'openid/yadis/services' require 'openid/yadis/filters' require 'openid/consumer/html_parse' require 'openid/yadis/xrires' module OpenID OPENID_1_0_NS = 'http://openid.net/xmlns/1.0' OPENID_IDP_2_0_TYPE = 'http://specs.openid.net/auth/2.0/server' OPENID_2_0_TYPE = 'http://specs.openid.net/auth/2.0/signon' OPENID_1_1_TYPE = 'http://openid.net/signon/1.1' OPENID_1_0_TYPE = 'http://openid.net/signon/1.0' OPENID_1_0_MESSAGE_NS = OPENID1_NS OPENID_2_0_MESSAGE_NS = OPENID2_NS # Object representing an OpenID service endpoint. class OpenIDServiceEndpoint # OpenID service type URIs, listed in order of preference. The # ordering of this list affects yadis and XRI service discovery. OPENID_TYPE_URIS = [ OPENID_IDP_2_0_TYPE, OPENID_2_0_TYPE, OPENID_1_1_TYPE, OPENID_1_0_TYPE, ] # the verified identifier. attr_accessor :claimed_id # For XRI, the persistent identifier. attr_accessor :canonical_id attr_accessor :server_url, :type_uris, :local_id, :used_yadis def initialize @claimed_id = nil @server_url = nil @type_uris = [] @local_id = nil @canonical_id = nil @used_yadis = false # whether this came from an XRDS @display_identifier = nil end def display_identifier return @display_identifier if @display_identifier return @claimed_id if @claimed_id.nil? begin parsed_identifier = URI.parse(@claimed_id) rescue URI::InvalidURIError raise ProtocolError, "Claimed identifier #{claimed_id} is not a valid URI" end return @claimed_id if not parsed_identifier.fragment disp = parsed_identifier disp.fragment = nil return disp.to_s end def display_identifier=(display_identifier) @display_identifier = display_identifier end def uses_extension(extension_uri) return @type_uris.member?(extension_uri) end def preferred_namespace if (@type_uris.member?(OPENID_IDP_2_0_TYPE) or @type_uris.member?(OPENID_2_0_TYPE)) return OPENID_2_0_MESSAGE_NS else return OPENID_1_0_MESSAGE_NS end end def supports_type(type_uri) # Does this endpoint support this type? # # I consider C{/server} endpoints to implicitly support C{/signon}. ( @type_uris.member?(type_uri) or (type_uri == OPENID_2_0_TYPE and is_op_identifier()) ) end def compatibility_mode return preferred_namespace() != OPENID_2_0_MESSAGE_NS end def is_op_identifier return @type_uris.member?(OPENID_IDP_2_0_TYPE) end def parse_service(yadis_url, uri, type_uris, service_element) # Set the state of this object based on the contents of the # service element. @type_uris = type_uris @server_url = uri @used_yadis = true if !is_op_identifier() # XXX: This has crappy implications for Service elements that # contain both 'server' and 'signon' Types. But that's a # pathological configuration anyway, so I don't think I care. @local_id = OpenID.find_op_local_identifier(service_element, @type_uris) @claimed_id = yadis_url end end def get_local_id # Return the identifier that should be sent as the # openid.identity parameter to the server. if @local_id.nil? and @canonical_id.nil? return @claimed_id else return (@local_id or @canonical_id) end end def to_session_value Hash[*(instance_variables.map{|name| [name, instance_variable_get(name)] }.flatten(1))] end def ==(other) to_session_value == other.to_session_value end def self.from_session_value(value) return value unless value.is_a?(Hash) self.new.tap do |endpoint| value.each do |name, val| endpoint.instance_variable_set(name, val) end end end def self.from_basic_service_endpoint(endpoint) # Create a new instance of this class from the endpoint object # passed in. # # @return: nil or OpenIDServiceEndpoint for this endpoint object""" type_uris = endpoint.match_types(OPENID_TYPE_URIS) # If any Type URIs match and there is an endpoint URI specified, # then this is an OpenID endpoint if (!type_uris.nil? and !type_uris.empty?) and !endpoint.uri.nil? openid_endpoint = self.new openid_endpoint.parse_service( endpoint.yadis_url, endpoint.uri, endpoint.type_uris, endpoint.service_element) else openid_endpoint = nil end return openid_endpoint end def self.from_html(uri, html) # Parse the given document as HTML looking for an OpenID # # @rtype: [OpenIDServiceEndpoint] discovery_types = [ [OPENID_2_0_TYPE, 'openid2.provider', 'openid2.local_id'], [OPENID_1_1_TYPE, 'openid.server', 'openid.delegate'], ] link_attrs = OpenID.parse_link_attrs(html) services = [] discovery_types.each { |type_uri, op_endpoint_rel, local_id_rel| op_endpoint_url = OpenID.find_first_href(link_attrs, op_endpoint_rel) if !op_endpoint_url next end service = self.new service.claimed_id = uri service.local_id = OpenID.find_first_href(link_attrs, local_id_rel) service.server_url = op_endpoint_url service.type_uris = [type_uri] services << service } return services end def self.from_xrds(uri, xrds) # Parse the given document as XRDS looking for OpenID services. # # @rtype: [OpenIDServiceEndpoint] # # @raises L{XRDSError}: When the XRDS does not parse. return Yadis::apply_filter(uri, xrds, self) end def self.from_discovery_result(discoveryResult) # Create endpoints from a DiscoveryResult. # # @type discoveryResult: L{DiscoveryResult} # # @rtype: list of L{OpenIDServiceEndpoint} # # @raises L{XRDSError}: When the XRDS does not parse. if discoveryResult.is_xrds() meth = self.method('from_xrds') else meth = self.method('from_html') end return meth.call(discoveryResult.normalized_uri, discoveryResult.response_text) end def self.from_op_endpoint_url(op_endpoint_url) # Construct an OP-Identifier OpenIDServiceEndpoint object for # a given OP Endpoint URL # # @param op_endpoint_url: The URL of the endpoint # @rtype: OpenIDServiceEndpoint service = self.new service.server_url = op_endpoint_url service.type_uris = [OPENID_IDP_2_0_TYPE] return service end def to_s return sprintf("<%s server_url=%s claimed_id=%s " + "local_id=%s canonical_id=%s used_yadis=%s>", self.class, @server_url, @claimed_id, @local_id, @canonical_id, @used_yadis) end end def self.find_op_local_identifier(service_element, type_uris) # Find the OP-Local Identifier for this xrd:Service element. # # This considers openid:Delegate to be a synonym for xrd:LocalID # if both OpenID 1.X and OpenID 2.0 types are present. If only # OpenID 1.X is present, it returns the value of # openid:Delegate. If only OpenID 2.0 is present, it returns the # value of xrd:LocalID. If there is more than one LocalID tag and # the values are different, it raises a DiscoveryFailure. This is # also triggered when the xrd:LocalID and openid:Delegate tags are # different. # XXX: Test this function on its own! # Build the list of tags that could contain the OP-Local # Identifier local_id_tags = [] if type_uris.member?(OPENID_1_1_TYPE) or type_uris.member?(OPENID_1_0_TYPE) # local_id_tags << Yadis::nsTag(OPENID_1_0_NS, 'openid', 'Delegate') service_element.add_namespace('openid', OPENID_1_0_NS) local_id_tags << "openid:Delegate" end if type_uris.member?(OPENID_2_0_TYPE) # local_id_tags.append(Yadis::nsTag(XRD_NS_2_0, 'xrd', 'LocalID')) service_element.add_namespace('xrd', Yadis::XRD_NS_2_0) local_id_tags << "xrd:LocalID" end # Walk through all the matching tags and make sure that they all # have the same value local_id = nil local_id_tags.each { |local_id_tag| service_element.each_element(local_id_tag) { |local_id_element| if local_id.nil? local_id = local_id_element.text elsif local_id != local_id_element.text format = 'More than one %s tag found in one service element' message = sprintf(format, local_id_tag) raise DiscoveryFailure.new(message, nil) end } } return local_id end def self.normalize_xri(xri) # Normalize an XRI, stripping its scheme if present m = /^xri:\/\/(.*)/.match(xri) xri = m[1] if m return xri end def self.normalize_url(url) # Normalize a URL, converting normalization failures to # DiscoveryFailure begin normalized = URINorm.urinorm(url) rescue URI::Error => why raise DiscoveryFailure.new("Error normalizing #{url}: #{why.message}", nil) else defragged = URI::parse(normalized) defragged.fragment = nil return defragged.normalize.to_s end end def self.best_matching_service(service, preferred_types) # Return the index of the first matching type, or something higher # if no type matches. # # This provides an ordering in which service elements that contain # a type that comes earlier in the preferred types list come # before service elements that come later. If a service element # has more than one type, the most preferred one wins. preferred_types.each_with_index { |value, index| if service.type_uris.member?(value) return index end } return preferred_types.length end def self.arrange_by_type(service_list, preferred_types) # Rearrange service_list in a new list so services are ordered by # types listed in preferred_types. Return the new list. # Build a list with the service elements in tuples whose # comparison will prefer the one with the best matching service prio_services = [] service_list.each_with_index { |s, index| prio_services << [best_matching_service(s, preferred_types), index, s] } prio_services.sort! # Now that the services are sorted by priority, remove the sort # keys from the list. (0...prio_services.length).each { |i| prio_services[i] = prio_services[i][2] } return prio_services end def self.get_op_or_user_services(openid_services) # Extract OP Identifier services. If none found, return the rest, # sorted with most preferred first according to # OpenIDServiceEndpoint.openid_type_uris. # # openid_services is a list of OpenIDServiceEndpoint objects. # # Returns a list of OpenIDServiceEndpoint objects. op_services = arrange_by_type(openid_services, [OPENID_IDP_2_0_TYPE]) openid_services = arrange_by_type(openid_services, OpenIDServiceEndpoint::OPENID_TYPE_URIS) if !op_services.empty? return op_services else return openid_services end end def self.discover_yadis(uri) # Discover OpenID services for a URI. Tries Yadis and falls back # on old-style discovery if Yadis fails. # # @param uri: normalized identity URL # @type uri: str # # @return: (claimed_id, services) # @rtype: (str, list(OpenIDServiceEndpoint)) # # @raises DiscoveryFailure: when discovery fails. # Might raise a yadis.discover.DiscoveryFailure if no document # came back for that URI at all. I don't think falling back to # OpenID 1.0 discovery on the same URL will help, so don't bother # to catch it. response = Yadis.discover(uri) yadis_url = response.normalized_uri body = response.response_text begin openid_services = OpenIDServiceEndpoint.from_xrds(yadis_url, body) rescue Yadis::XRDSError # Does not parse as a Yadis XRDS file openid_services = [] end if openid_services.empty? # Either not an XRDS or there are no OpenID services. if response.is_xrds # if we got the Yadis content-type or followed the Yadis # header, re-fetch the document without following the Yadis # header, with no Accept header. return self.discover_no_yadis(uri) end # Try to parse the response as HTML. # openid_services = OpenIDServiceEndpoint.from_html(yadis_url, body) end return [yadis_url, self.get_op_or_user_services(openid_services)] end def self.discover_xri(iname) endpoints = [] iname = self.normalize_xri(iname) begin canonical_id, services = Yadis::XRI::ProxyResolver.new().query( iname ) if canonical_id.nil? raise Yadis::XRDSError.new(sprintf('No CanonicalID found for XRI %s', iname)) end flt = Yadis.make_filter(OpenIDServiceEndpoint) services.each { |service_element| endpoints += flt.get_service_endpoints(iname, service_element) } rescue Yadis::XRDSError => why Util.log('xrds error on ' + iname + ': ' + why.to_s) end endpoints.each { |endpoint| # Is there a way to pass this through the filter to the endpoint # constructor instead of tacking it on after? endpoint.canonical_id = canonical_id endpoint.claimed_id = canonical_id endpoint.display_identifier = iname } # FIXME: returned xri should probably be in some normal form return [iname, self.get_op_or_user_services(endpoints)] end def self.discover_no_yadis(uri) http_resp = OpenID.fetch(uri) if http_resp.code != "200" and http_resp.code != "206" raise DiscoveryFailure.new( "HTTP Response status from identity URL host is not \"200\". "\ "Got status #{http_resp.code.inspect}", http_resp) end claimed_id = http_resp.final_url openid_services = OpenIDServiceEndpoint.from_html( claimed_id, http_resp.body) return [claimed_id, openid_services] end def self.discover_uri(uri) # Hack to work around URI parsing for URls with *no* scheme. if uri.index("://").nil? uri = 'http://' + uri end begin parsed = URI::parse(uri) rescue URI::InvalidURIError => why raise DiscoveryFailure.new("URI is not valid: #{why.message}", nil) end if !parsed.scheme.nil? and !parsed.scheme.empty? if !['http', 'https'].member?(parsed.scheme) raise DiscoveryFailure.new( "URI scheme #{parsed.scheme} is not HTTP or HTTPS", nil) end end uri = self.normalize_url(uri) claimed_id, openid_services = self.discover_yadis(uri) claimed_id = self.normalize_url(claimed_id) return [claimed_id, openid_services] end def self.discover(identifier) if Yadis::XRI::identifier_scheme(identifier) == :xri discover_xri(identifier) else return discover_uri(identifier) end end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/responses.rb0000644000175000017500000001070512512544714023544 0ustar sbadiasbadiamodule OpenID class Consumer # Code returned when either the of the # OpenID::OpenIDConsumer.begin_auth or OpenID::OpenIDConsumer.complete_auth # methods return successfully. SUCCESS = :success # Code OpenID::OpenIDConsumer.complete_auth # returns when the value it received indicated an invalid login. FAILURE = :failure # Code returned by OpenIDConsumer.complete_auth when the user # cancels the operation from the server. CANCEL = :cancel # Code returned by OpenID::OpenIDConsumer.complete_auth when the # OpenIDConsumer instance is in immediate mode and ther server sends back a # URL for the user to login with. SETUP_NEEDED = :setup_needed module Response attr_reader :endpoint def status self.class::STATUS end # The identity URL that has been authenticated; the Claimed Identifier. # See also display_identifier. def identity_url @endpoint ? @endpoint.claimed_id : nil end # The display identifier is related to the Claimed Identifier, but the # two are not always identical. The display identifier is something the # user should recognize as what they entered, whereas the response's # claimed identifier (in the identity_url attribute) may have extra # information for better persistence. # # URLs will be stripped of their fragments for display. XRIs will # display the human-readable identifier (i-name) instead of the # persistent identifier (i-number). # # Use the display identifier in your user interface. Use identity_url # for querying your database or authorization server, or other # identifier equality comparisons. def display_identifier @endpoint ? @endpoint.display_identifier : nil end end # A successful acknowledgement from the OpenID server that the # supplied URL is, indeed controlled by the requesting agent. class SuccessResponse include Response STATUS = SUCCESS attr_reader :message, :signed_fields def initialize(endpoint, message, signed_fields) # Don't use :endpoint=, because endpoint should never be nil # for a successfull transaction. @endpoint = endpoint @identity_url = endpoint.claimed_id @message = message @signed_fields = signed_fields end # Was this authentication response an OpenID 1 authentication # response? def is_openid1 @message.is_openid1 end # Return whether a particular key is signed, regardless of its # namespace alias def signed?(ns_uri, ns_key) @signed_fields.member?(@message.get_key(ns_uri, ns_key)) end # Return the specified signed field if available, otherwise # return default def get_signed(ns_uri, ns_key, default=nil) if signed?(ns_uri, ns_key) return @message.get_arg(ns_uri, ns_key, default) else return default end end # Get signed arguments from the response message. Return a dict # of all arguments in the specified namespace. If any of the # arguments are not signed, return nil. def get_signed_ns(ns_uri) msg_args = @message.get_args(ns_uri) msg_args.each_key do |key| if !signed?(ns_uri, key) return nil end end return msg_args end # Return response arguments in the specified namespace. # If require_signed is true and the arguments are not signed, # return nil. def extension_response(namespace_uri, require_signed) if require_signed get_signed_ns(namespace_uri) else @message.get_args(namespace_uri) end end end class FailureResponse include Response STATUS = FAILURE attr_reader :message, :contact, :reference def initialize(endpoint, message, contact=nil, reference=nil) @endpoint = endpoint @message = message @contact = contact @reference = reference end end class CancelResponse include Response STATUS = CANCEL def initialize(endpoint) @endpoint = endpoint end end class SetupNeededResponse include Response STATUS = SETUP_NEEDED attr_reader :setup_url def initialize(endpoint, setup_url) @endpoint = endpoint @setup_url = setup_url end end end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/session.rb0000644000175000017500000000140712512544714023205 0ustar sbadiasbadiamodule OpenID class Consumer class Session def initialize(session, decode_klass = nil) @session = session @decode_klass = decode_klass end def [](key) val = @session[key] @decode_klass ? @decode_klass.from_session_value(val) : val end def []=(key, val) @session[key] = to_session_value(val) end def keys @session.keys end private def to_session_value(val) case val when Array val.map{|ele| to_session_value(ele) } when Hash Hash[*(val.map{|k,v| [k, to_session_value(v)] }.flatten(1))] else val.respond_to?(:to_session_value) ? val.to_session_value : val end end end end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/html_parse.rb0000644000175000017500000000703512512544714023663 0ustar sbadiasbadiarequire "openid/yadis/htmltokenizer" module OpenID # Stuff to remove before we start looking for tags REMOVED_RE = / # Comments # CDATA blocks | # script blocks | ]*>.*?<\/script> /mix def OpenID.openid_unescape(s) s.gsub('&','&').gsub('<','<').gsub('>','>').gsub('"','"') end def OpenID.unescape_hash(h) newh = {} h.map{|k,v| newh[k]=openid_unescape(v) } newh end def OpenID.parse_link_attrs(html) begin stripped = html.gsub(REMOVED_RE,'') rescue ArgumentError begin stripped = html.encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '').gsub(REMOVED_RE,'') rescue Encoding::UndefinedConversionError, Encoding::ConverterNotFoundError # needed for a problem in JRuby where it can't handle the conversion. # see details here: https://github.com/jruby/jruby/issues/829 stripped = html.encode('UTF-8', 'ASCII', :invalid => :replace, :undef => :replace, :replace => '').gsub(REMOVED_RE,'') end end parser = HTMLTokenizer.new(stripped) links = [] # to keep track of whether or not we are in the head element in_head = false in_html = false saw_head = false begin while el = parser.getTag('head', '/head', 'link', 'body', '/body', 'html', '/html') # we are leaving head or have reached body, so we bail return links if ['/head', 'body', '/body', '/html'].member?(el.tag_name) # enforce html > head > link if el.tag_name == 'html' in_html = true end next unless in_html if el.tag_name == 'head' if saw_head return links #only allow one head end saw_head = true unless el.to_s[-2] == 47 # tag ends with a /: a short tag in_head = true end end next unless in_head return links if el.tag_name == 'html' if el.tag_name == 'link' links << unescape_hash(el.attr_hash) end end rescue Exception # just stop parsing if there's an error end return links end def OpenID.rel_matches(rel_attr, target_rel) # Does this target_rel appear in the rel_str? # XXX: TESTME rels = rel_attr.strip().split() rels.each { |rel| rel = rel.downcase if rel == target_rel return true end } return false end def OpenID.link_has_rel(link_attrs, target_rel) # Does this link have target_rel as a relationship? # XXX: TESTME rel_attr = link_attrs['rel'] return (rel_attr and rel_matches(rel_attr, target_rel)) end def OpenID.find_links_rel(link_attrs_list, target_rel) # Filter the list of link attributes on whether it has target_rel # as a relationship. # XXX: TESTME matchesTarget = lambda { |attrs| link_has_rel(attrs, target_rel) } result = [] link_attrs_list.each { |item| if matchesTarget.call(item) result << item end } return result end def OpenID.find_first_href(link_attrs_list, target_rel) # Return the value of the href attribute for the first link tag in # the list that has target_rel as a relationship. # XXX: TESTME matches = find_links_rel(link_attrs_list, target_rel) if !matches or matches.empty? return nil end first = matches[0] return first['href'] end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/discovery_manager.rb0000644000175000017500000000711212512544714025222 0ustar sbadiasbadiamodule OpenID class Consumer # A set of discovered services, for tracking which providers have # been attempted for an OpenID identifier class DiscoveredServices attr_reader :current def initialize(starting_url, yadis_url, services) @starting_url = starting_url @yadis_url = yadis_url @services = services.dup @current = nil end def next @current = @services.shift end def for_url?(url) [@starting_url, @yadis_url].member?(url) end def started? !@current.nil? end def empty? @services.empty? end def to_session_value services = @services.map{|s| s.respond_to?(:to_session_value) ? s.to_session_value : s } current_val = @current.respond_to?(:to_session_value) ? @current.to_session_value : @current { 'starting_url' => @starting_url, 'yadis_url' => @yadis_url, 'services' => services, 'current' => current_val } end def ==(other) to_session_value == other.to_session_value end def self.from_session_value(value) return value unless value.is_a?(Hash) services = value['services'].map{|s| OpenID::OpenIDServiceEndpoint.from_session_value(s) } current = OpenID::OpenIDServiceEndpoint.from_session_value(value['current']) obj = self.new(value['starting_url'], value['yadis_url'], services) obj.instance_variable_set("@current", current) obj end end # Manages calling discovery and tracking which endpoints have # already been attempted. class DiscoveryManager def initialize(session, url, session_key_suffix=nil) @url = url @session = OpenID::Consumer::Session.new(session, DiscoveredServices) @session_key_suffix = session_key_suffix || 'auth' end def get_next_service manager = get_manager if !manager.nil? && manager.empty? destroy_manager manager = nil end if manager.nil? yadis_url, services = yield @url manager = create_manager(yadis_url, services) end if !manager.nil? service = manager.next store(manager) else service = nil end return service end def cleanup(force=false) manager = get_manager(force) if !manager.nil? service = manager.current destroy_manager(force) else service = nil end return service end protected def get_manager(force=false) manager = load if force || manager.nil? || manager.for_url?(@url) return manager else return nil end end def create_manager(yadis_url, services) manager = get_manager if !manager.nil? raise StandardError, "There is already a manager for #{yadis_url}" end if services.empty? return nil end manager = DiscoveredServices.new(@url, yadis_url, services) store(manager) return manager end def destroy_manager(force=false) if !get_manager(force).nil? destroy! end end def session_key 'OpenID::Consumer::DiscoveredServices::' + @session_key_suffix end def store(manager) @session[session_key] = manager end def load @session[session_key] end def destroy! @session[session_key] = nil end end end end ruby-openid-2.7.0debian.orig/lib/openid/consumer/checkid_request.rb0000644000175000017500000001631412512544714024667 0ustar sbadiasbadiarequire "openid/message" require "openid/util" module OpenID class Consumer # An object that holds the state necessary for generating an # OpenID authentication request. This object holds the association # with the server and the discovered information with which the # request will be made. # # It is separate from the consumer because you may wish to add # things to the request before sending it on its way to the # server. It also has serialization options that let you encode # the authentication request as a URL or as a form POST. class CheckIDRequest attr_accessor :return_to_args, :message attr_reader :endpoint # Users of this library should not create instances of this # class. Instances of this class are created by the library # when needed. def initialize(assoc, endpoint) @assoc = assoc @endpoint = endpoint @return_to_args = {} @message = Message.new(endpoint.preferred_namespace) @anonymous = false end attr_reader :anonymous # Set whether this request should be made anonymously. If a # request is anonymous, the identifier will not be sent in the # request. This is only useful if you are making another kind of # request with an extension in this request. # # Anonymous requests are not allowed when the request is made # with OpenID 1. def anonymous=(is_anonymous) if is_anonymous && @message.is_openid1 raise ArgumentError, ("OpenID1 requests MUST include the "\ "identifier in the request") end @anonymous = is_anonymous end # Add an object that implements the extension interface for # adding arguments to an OpenID message to this checkid request. # # extension_request: an OpenID::Extension object. def add_extension(extension_request) extension_request.to_message(@message) end # Add an extension argument to this OpenID authentication # request. You probably want to use add_extension and the # OpenID::Extension interface. # # Use caution when adding arguments, because they will be # URL-escaped and appended to the redirect URL, which can easily # get quite long. def add_extension_arg(namespace, key, value) @message.set_arg(namespace, key, value) end # Produce a OpenID::Message representing this request. # # Not specifying a return_to URL means that the user will not be # returned to the site issuing the request upon its completion. # # If immediate mode is requested, the OpenID provider is to send # back a response immediately, useful for behind-the-scenes # authentication attempts. Otherwise the OpenID provider may # engage the user before providing a response. This is the # default case, as the user may need to provide credentials or # approve the request before a positive response can be sent. def get_message(realm, return_to=nil, immediate=false) if !return_to.nil? return_to = Util.append_args(return_to, @return_to_args) elsif immediate raise ArgumentError, ('"return_to" is mandatory when using '\ '"checkid_immediate"') elsif @message.is_openid1 raise ArgumentError, ('"return_to" is mandatory for OpenID 1 '\ 'requests') elsif @return_to_args.empty? raise ArgumentError, ('extra "return_to" arguments were specified, '\ 'but no return_to was specified') end message = @message.copy mode = immediate ? 'checkid_immediate' : 'checkid_setup' message.set_arg(OPENID_NS, 'mode', mode) realm_key = message.is_openid1 ? 'trust_root' : 'realm' message.set_arg(OPENID_NS, realm_key, realm) if !return_to.nil? message.set_arg(OPENID_NS, 'return_to', return_to) end if not @anonymous if @endpoint.is_op_identifier # This will never happen when we're in OpenID 1 # compatibility mode, as long as is_op_identifier() # returns false whenever preferred_namespace returns # OPENID1_NS. claimed_id = request_identity = IDENTIFIER_SELECT else request_identity = @endpoint.get_local_id claimed_id = @endpoint.claimed_id end # This is true for both OpenID 1 and 2 message.set_arg(OPENID_NS, 'identity', request_identity) if message.is_openid2 message.set_arg(OPENID2_NS, 'claimed_id', claimed_id) end end if @assoc && (message.is_openid1 || !['checkid_setup', 'checkid_immediate'].include?(mode)) message.set_arg(OPENID_NS, 'assoc_handle', @assoc.handle) assoc_log_msg = "with assocication #{@assoc.handle}" else assoc_log_msg = 'using stateless mode.' end Util.log("Generated #{mode} request to #{@endpoint.server_url} "\ "#{assoc_log_msg}") return message end # Returns a URL with an encoded OpenID request. # # The resulting URL is the OpenID provider's endpoint URL with # parameters appended as query arguments. You should redirect # the user agent to this URL. # # OpenID 2.0 endpoints also accept POST requests, see # 'send_redirect?' and 'form_markup'. def redirect_url(realm, return_to=nil, immediate=false) message = get_message(realm, return_to, immediate) return message.to_url(@endpoint.server_url) end # Get html for a form to submit this request to the IDP. # # form_tag_attrs is a hash of attributes to be added to the form # tag. 'accept-charset' and 'enctype' have defaults that can be # overridden. If a value is supplied for 'action' or 'method', # it will be replaced. def form_markup(realm, return_to=nil, immediate=false, form_tag_attrs=nil) message = get_message(realm, return_to, immediate) return message.to_form_markup(@endpoint.server_url, form_tag_attrs) end # Get a complete HTML document that autosubmits the request to the IDP # with javascript. This method wraps form_markup - see that method's # documentation for help with the parameters. def html_markup(realm, return_to=nil, immediate=false, form_tag_attrs=nil) Util.auto_submit_html(form_markup(realm, return_to, immediate, form_tag_attrs)) end # Should this OpenID authentication request be sent as a HTTP # redirect or as a POST (form submission)? # # This takes the same parameters as redirect_url or form_markup def send_redirect?(realm, return_to=nil, immediate=false) if @endpoint.compatibility_mode return true else url = redirect_url(realm, return_to, immediate) return url.length <= OPENID1_URL_LIMIT end end end end end ruby-openid-2.7.0debian.orig/lib/openid/message.rb0000644000175000017500000004020212512544714021307 0ustar sbadiasbadiarequire 'openid/util' require 'openid/kvform' module OpenID IDENTIFIER_SELECT = 'http://specs.openid.net/auth/2.0/identifier_select' # URI for Simple Registration extension, the only commonly deployed # OpenID 1.x extension, and so a special case. SREG_URI = 'http://openid.net/sreg/1.0' # The OpenID 1.x namespace URIs OPENID1_NS = 'http://openid.net/signon/1.0' OPENID11_NS = 'http://openid.net/signon/1.1' OPENID1_NAMESPACES = [OPENID1_NS, OPENID11_NS] # The OpenID 2.0 namespace URI OPENID2_NS = 'http://specs.openid.net/auth/2.0' # The namespace consisting of pairs with keys that are prefixed with # "openid." but not in another namespace. NULL_NAMESPACE = :null_namespace # The null namespace, when it is an allowed OpenID namespace OPENID_NS = :openid_namespace # The top-level namespace, excluding all pairs with keys that start # with "openid." BARE_NS = :bare_namespace # Limit, in bytes, of identity provider and return_to URLs, # including response payload. See OpenID 1.1 specification, # Appendix D. OPENID1_URL_LIMIT = 2047 # All OpenID protocol fields. Used to check namespace aliases. OPENID_PROTOCOL_FIELDS = [ 'ns', 'mode', 'error', 'return_to', 'contact', 'reference', 'signed', 'assoc_type', 'session_type', 'dh_modulus', 'dh_gen', 'dh_consumer_public', 'claimed_id', 'identity', 'realm', 'invalidate_handle', 'op_endpoint', 'response_nonce', 'sig', 'assoc_handle', 'trust_root', 'openid', ] # Sentinel used for Message implementation to indicate that getArg # should raise an exception instead of returning a default. NO_DEFAULT = :no_default # Raised if the generic OpenID namespace is accessed when there # is no OpenID namespace set for this message. class UndefinedOpenIDNamespace < Exception; end # Raised when an alias or namespace URI has already been registered. class NamespaceAliasRegistrationError < Exception; end # Raised if openid.ns is not a recognized value. # See Message class variable @@allowed_openid_namespaces class InvalidOpenIDNamespace < Exception; end class Message attr_reader :namespaces # Raised when key lookup fails class KeyNotFound < IndexError ; end # Namespace / alias registration map. See # register_namespace_alias. @@registered_aliases = {} # Registers a (namespace URI, alias) mapping in a global namespace # alias map. Raises NamespaceAliasRegistrationError if either the # namespace URI or alias has already been registered with a # different value. This function is required if you want to use a # namespace with an OpenID 1 message. def Message.register_namespace_alias(namespace_uri, alias_) if @@registered_aliases[alias_] == namespace_uri return end if @@registered_aliases.values.include?(namespace_uri) raise NamespaceAliasRegistrationError, 'Namespace uri #{namespace_uri} already registered' end if @@registered_aliases.member?(alias_) raise NamespaceAliasRegistrationError, 'Alias #{alias_} already registered' end @@registered_aliases[alias_] = namespace_uri end @@allowed_openid_namespaces = [OPENID1_NS, OPENID2_NS, OPENID11_NS] # Raises InvalidNamespaceError if you try to instantiate a Message # with a namespace not in the above allowed list def initialize(openid_namespace=nil) @args = {} @namespaces = NamespaceMap.new if openid_namespace implicit = OPENID1_NAMESPACES.member? openid_namespace self.set_openid_namespace(openid_namespace, implicit) else @openid_ns_uri = nil end end # Construct a Message containing a set of POST arguments. # Raises InvalidNamespaceError if you try to instantiate a Message # with a namespace not in the above allowed list def Message.from_post_args(args) m = Message.new openid_args = {} args.each do |key,value| if value.is_a?(Array) raise ArgumentError, "Query dict must have one value for each key, " + "not lists of values. Query is #{args.inspect}" end prefix, rest = key.split('.', 2) if prefix != 'openid' or rest.nil? m.set_arg(BARE_NS, key, value) else openid_args[rest] = value end end m._from_openid_args(openid_args) return m end # Construct a Message from a parsed KVForm message. # Raises InvalidNamespaceError if you try to instantiate a Message # with a namespace not in the above allowed list def Message.from_openid_args(openid_args) m = Message.new m._from_openid_args(openid_args) return m end # Raises InvalidNamespaceError if you try to instantiate a Message # with a namespace not in the above allowed list def _from_openid_args(openid_args) ns_args = [] # resolve namespaces openid_args.each { |rest, value| ns_alias, ns_key = rest.split('.', 2) if ns_key.nil? ns_alias = NULL_NAMESPACE ns_key = rest end if ns_alias == 'ns' @namespaces.add_alias(value, ns_key) elsif ns_alias == NULL_NAMESPACE and ns_key == 'ns' set_openid_namespace(value, false) else ns_args << [ns_alias, ns_key, value] end } # implicitly set an OpenID 1 namespace unless get_openid_namespace set_openid_namespace(OPENID1_NS, true) end # put the pairs into the appropriate namespaces ns_args.each { |ns_alias, ns_key, value| ns_uri = @namespaces.get_namespace_uri(ns_alias) unless ns_uri ns_uri = _get_default_namespace(ns_alias) unless ns_uri ns_uri = get_openid_namespace ns_key = "#{ns_alias}.#{ns_key}" else @namespaces.add_alias(ns_uri, ns_alias, true) end end self.set_arg(ns_uri, ns_key, value) } end def _get_default_namespace(mystery_alias) # only try to map an alias to a default if it's an # OpenID 1.x namespace if is_openid1 @@registered_aliases[mystery_alias] end end def set_openid_namespace(openid_ns_uri, implicit) if !@@allowed_openid_namespaces.include?(openid_ns_uri) raise InvalidOpenIDNamespace, "Invalid null namespace: #{openid_ns_uri}" end @namespaces.add_alias(openid_ns_uri, NULL_NAMESPACE, implicit) @openid_ns_uri = openid_ns_uri end def get_openid_namespace return @openid_ns_uri end def is_openid1 return OPENID1_NAMESPACES.member?(@openid_ns_uri) end def is_openid2 return @openid_ns_uri == OPENID2_NS end # Create a message from a KVForm string def Message.from_kvform(kvform_string) return Message.from_openid_args(Util.kv_to_dict(kvform_string)) end def copy return Marshal.load(Marshal.dump(self)) end # Return all arguments with "openid." in from of namespaced arguments. def to_post_args args = {} # add namespace defs to the output @namespaces.each { |ns_uri, ns_alias| if @namespaces.implicit?(ns_uri) next end if ns_alias == NULL_NAMESPACE ns_key = 'openid.ns' else ns_key = 'openid.ns.' + ns_alias end args[ns_key] = ns_uri } @args.each { |k, value| ns_uri, ns_key = k key = get_key(ns_uri, ns_key) args[key] = value } return args end # Return all namespaced arguments, failing if any non-namespaced arguments # exist. def to_args post_args = self.to_post_args kvargs = {} post_args.each { |k,v| if !k.start_with?('openid.') raise ArgumentError, "This message can only be encoded as a POST, because it contains arguments that are not prefixed with 'openid.'" else kvargs[k[7..-1]] = v end } return kvargs end # Generate HTML form markup that contains the values in this # message, to be HTTP POSTed as x-www-form-urlencoded UTF-8. def to_form_markup(action_url, form_tag_attrs=nil, submit_text='Continue') form_tag_attr_map = {} if form_tag_attrs form_tag_attrs.each { |name, attr| form_tag_attr_map[name] = attr } end form_tag_attr_map['action'] = action_url form_tag_attr_map['method'] = 'post' form_tag_attr_map['accept-charset'] = 'UTF-8' form_tag_attr_map['enctype'] = 'application/x-www-form-urlencoded' markup = "
#{key} not in this message" else default end } end # Get the arguments that are defined for this namespace URI. def get_args(namespace) namespace = _fix_ns(namespace) args = {} @args.each { |k,v| pair_ns, ns_key = k args[ns_key] = v if pair_ns == namespace } return args end # Set multiple key/value pairs in one call. def update_args(namespace, updates) namespace = _fix_ns(namespace) updates.each {|k,v| set_arg(namespace, k, v)} end # Set a single argument in this namespace def set_arg(namespace, key, value) namespace = _fix_ns(namespace) @args[[namespace, key].freeze] = value if namespace != BARE_NS @namespaces.add(namespace) end end # Remove a single argument from this namespace. def del_arg(namespace, key) namespace = _fix_ns(namespace) _key = [namespace, key] @args.delete(_key) end def ==(other) other.is_a?(self.class) && @args == other.instance_eval { @args } end def get_aliased_arg(aliased_key, default=nil) if aliased_key == 'ns' return get_openid_namespace() end ns_alias, key = aliased_key.split('.', 2) if ns_alias == 'ns' uri = @namespaces.get_namespace_uri(key) if uri.nil? and default == NO_DEFAULT raise KeyNotFound, "Namespace #{key} not defined when looking "\ "for #{aliased_key}" else return (uri.nil? ? default : uri) end end if key.nil? key = aliased_key ns = nil else ns = @namespaces.get_namespace_uri(ns_alias) end if ns.nil? key = aliased_key ns = get_openid_namespace end return get_arg(ns, key, default) end end # Maintains a bidirectional map between namespace URIs and aliases. class NamespaceMap def initialize @alias_to_namespace = {} @namespace_to_alias = {} @implicit_namespaces = [] end def get_alias(namespace_uri) @namespace_to_alias[namespace_uri] end def get_namespace_uri(namespace_alias) @alias_to_namespace[namespace_alias] end # Add an alias from this namespace URI to the alias. def add_alias(namespace_uri, desired_alias, implicit=false) # Check that desired_alias is not an openid protocol field as # per the spec. Util.assert(!OPENID_PROTOCOL_FIELDS.include?(desired_alias), "#{desired_alias} is not an allowed namespace alias") # check that there is not a namespace already defined for the # desired alias current_namespace_uri = @alias_to_namespace.fetch(desired_alias, nil) if current_namespace_uri and current_namespace_uri != namespace_uri raise IndexError, "Cannot map #{namespace_uri} to alias #{desired_alias}. #{current_namespace_uri} is already mapped to alias #{desired_alias}" end # Check that desired_alias does not contain a period as per the # spec. if desired_alias.is_a?(String) Util.assert(desired_alias.index('.').nil?, "#{desired_alias} must not contain a dot") end # check that there is not already a (different) alias for this # namespace URI. _alias = @namespace_to_alias[namespace_uri] if _alias and _alias != desired_alias raise IndexError, "Cannot map #{namespace_uri} to alias #{desired_alias}. It is already mapped to alias #{_alias}" end @alias_to_namespace[desired_alias] = namespace_uri @namespace_to_alias[namespace_uri] = desired_alias @implicit_namespaces << namespace_uri if implicit return desired_alias end # Add this namespace URI to the mapping, without caring what alias # it ends up with. def add(namespace_uri) # see if this namepace is already mapped to an alias _alias = @namespace_to_alias[namespace_uri] return _alias if _alias # Fall back to generating a numberical alias i = 0 while true _alias = 'ext' + i.to_s begin add_alias(namespace_uri, _alias) rescue IndexError i += 1 else return _alias end end raise StandardError, 'Unreachable' end def member?(namespace_uri) @namespace_to_alias.has_key?(namespace_uri) end def each @namespace_to_alias.each {|k,v| yield k,v} end def namespace_uris # Return an iterator over the namespace URIs return @namespace_to_alias.keys() end def implicit?(namespace_uri) return @implicit_namespaces.member?(namespace_uri) end def aliases # Return an iterator over the aliases return @alias_to_namespace.keys() end end end ruby-openid-2.7.0debian.orig/lib/openid/kvform.rb0000644000175000017500000000641412512544714021176 0ustar sbadiasbadia module OpenID class KVFormError < Exception end module Util def Util.seq_to_kv(seq, strict=false) # Represent a sequence of pairs of strings as newline-terminated # key:value pairs. The pairs are generated in the order given. # # @param seq: The pairs # # returns a string representation of the sequence err = lambda { |msg| msg = "seq_to_kv warning: #{msg}: #{seq.inspect}" if strict raise KVFormError, msg else Util.log(msg) end } lines = [] seq.each { |k, v| if !k.is_a?(String) err.call("Converting key to string: #{k.inspect}") k = k.to_s end if !k.index("\n").nil? raise KVFormError, "Invalid input for seq_to_kv: key contains newline: #{k.inspect}" end if !k.index(":").nil? raise KVFormError, "Invalid input for seq_to_kv: key contains colon: #{k.inspect}" end if k.strip() != k err.call("Key has whitespace at beginning or end: #{k.inspect}") end if !v.is_a?(String) err.call("Converting value to string: #{v.inspect}") v = v.to_s end if !v.index("\n").nil? raise KVFormError, "Invalid input for seq_to_kv: value contains newline: #{v.inspect}" end if v.strip() != v err.call("Value has whitespace at beginning or end: #{v.inspect}") end lines << k + ":" + v + "\n" } return lines.join("") end def Util.kv_to_seq(data, strict=false) # After one parse, seq_to_kv and kv_to_seq are inverses, with no # warnings: # # seq = kv_to_seq(s) # seq_to_kv(kv_to_seq(seq)) == seq err = lambda { |msg| msg = "kv_to_seq warning: #{msg}: #{data.inspect}" if strict raise KVFormError, msg else Util.log(msg) end } lines = data.split("\n") if data.length == 0 return [] end if data[-1].chr != "\n" err.call("Does not end in a newline") # We don't expect the last element of lines to be an empty # string because split() doesn't behave that way. end pairs = [] line_num = 0 lines.each { |line| line_num += 1 # Ignore blank lines if line.strip() == "" next end pair = line.split(':', 2) if pair.length == 2 k, v = pair k_s = k.strip() if k_s != k msg = "In line #{line_num}, ignoring leading or trailing whitespace in key #{k.inspect}" err.call(msg) end if k_s.length == 0 err.call("In line #{line_num}, got empty key") end v_s = v.strip() if v_s != v msg = "In line #{line_num}, ignoring leading or trailing whitespace in value #{v.inspect}" err.call(msg) end pairs << [k_s, v_s] else err.call("Line #{line_num} does not contain a colon") end } return pairs end def Util.dict_to_kv(d) return seq_to_kv(d.entries.sort) end def Util.kv_to_dict(s) seq = kv_to_seq(s) return Hash[*seq.flatten] end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/0000755000175000017500000000000012512544714020451 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/lib/openid/yadis/xrires.rb0000644000175000017500000000501112512544714022307 0ustar sbadiasbadiarequire "cgi" require "openid/yadis/xri" require "openid/yadis/xrds" require "openid/fetchers" module OpenID module Yadis module XRI class XRIHTTPError < StandardError; end class ProxyResolver DEFAULT_PROXY = 'http://proxy.xri.net/' def initialize(proxy_url=nil) if proxy_url @proxy_url = proxy_url else @proxy_url = DEFAULT_PROXY end @proxy_url += '/' unless @proxy_url.match('/$') end def query_url(xri, service_type=nil) # URI normal form has a leading xri://, but we need to strip # that off again for the QXRI. This is under discussion for # XRI Resolution WD 11. qxri = XRI.to_uri_normal(xri)[6..-1] hxri = @proxy_url + qxri args = {'_xrd_r' => 'application/xrds+xml'} if service_type args['_xrd_t'] = service_type else # don't perform service endpoint selection args['_xrd_r'] += ';sep=false' end return XRI.append_args(hxri, args) end def query(xri) # these can be query args or http headers, needn't be both. # headers = {'Accept' => 'application/xrds+xml;sep=true'} canonicalID = nil url = self.query_url(xri) begin response = OpenID.fetch(url) rescue raise XRIHTTPError, "Could not fetch #{xri}, #{$!}" end raise XRIHTTPError, "Could not fetch #{xri}" if response.nil? xrds = Yadis::parseXRDS(response.body) canonicalID = Yadis::get_canonical_id(xri, xrds) return canonicalID, Yadis::services(xrds) # TODO: # * If we do get hits for multiple service_types, we're almost # certainly going to have duplicated service entries and # broken priority ordering. end end def self.urlencode(args) a = [] args.each do |key, val| a << (CGI::escape(key) + "=" + CGI::escape(val)) end a.join("&") end def self.append_args(url, args) return url if args.length == 0 # rstrip question marks rstripped = url.dup while rstripped[-1].chr == '?' rstripped = rstripped[0...rstripped.length-1] end if rstripped.index('?') sep = '&' else sep = '?' end return url + sep + XRI.urlencode(args) end end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/htmltokenizer.rb0000644000175000017500000001664512512544714023711 0ustar sbadiasbadia# = HTMLTokenizer # # Author:: Ben Giddings (mailto:bg-rubyforge@infofiend.com) # Copyright:: Copyright (c) 2004 Ben Giddings # License:: Distributes under the same terms as Ruby # # # This is a partial port of the functionality behind Perl's TokeParser # Provided a page it progressively returns tokens from that page # # $Id: htmltokenizer.rb,v 1.7 2005/06/07 21:05:53 merc Exp $ # # A class to tokenize HTML. # # Example: # # page = " # # This is the title # # # #

This is the header

#

# This is the paragraph, it contains # links, # images
#        are
#        really cool. Ok, here is some more text and # another link. #

# # # " # toke = HTMLTokenizer.new(page) # # assert("

" == toke.getTag("h1", "h2", "h3").to_s.downcase) # assert(HTMLTag.new("") == toke.getTag("IMG", "A")) # assert("links" == toke.getTrimmedText) # assert(toke.getTag("IMG", "A").attr_hash['optional']) # assert("_blank" == toke.getTag("IMG", "A").attr_hash['target']) # class HTMLTokenizer @@version = 1.0 # Get version of HTMLTokenizer lib def self.version @@version end attr_reader :page # Create a new tokenizer, based on the content, used as a string. def initialize(content) @page = content.to_s @cur_pos = 0 end # Reset the parser, setting the current position back at the stop def reset @cur_pos = 0 end # Look at the next token, but don't actually grab it def peekNextToken if @cur_pos == @page.length then return nil end if ?< == @page[@cur_pos] # Next token is a tag of some kind if '!--' == @page[(@cur_pos + 1), 3] # Token is a comment tag_end = @page.index('-->', (@cur_pos + 1)) if tag_end.nil? raise HTMLTokenizerError, "No end found to started comment:\n#{@page[@cur_pos,80]}" end # p @page[@cur_pos .. (tag_end+2)] HTMLComment.new(@page[@cur_pos .. (tag_end + 2)]) else # Token is a html tag tag_end = @page.index('>', (@cur_pos + 1)) if tag_end.nil? raise HTMLTokenizerError, "No end found to started tag:\n#{@page[@cur_pos,80]}" end # p @page[@cur_pos .. tag_end] HTMLTag.new(@page[@cur_pos .. tag_end]) end else # Next token is text text_end = @page.index('<', @cur_pos) text_end = text_end.nil? ? -1 : (text_end - 1) # p @page[@cur_pos .. text_end] HTMLText.new(@page[@cur_pos .. text_end]) end end # Get the next token, returns an instance of # * HTMLText # * HTMLToken # * HTMLTag def getNextToken token = peekNextToken if token # @page = @page[token.raw.length .. -1] # @page.slice!(0, token.raw.length) @cur_pos += token.raw.length end #p token #print token.raw return token end # Get a tag from the specified set of desired tags. # For example: # foo = toke.getTag("h1", "h2", "h3") # Will return the next header tag encountered. def getTag(*sought_tags) sought_tags.collect! {|elm| elm.downcase} while (tag = getNextToken) if tag.kind_of?(HTMLTag) and (0 == sought_tags.length or sought_tags.include?(tag.tag_name)) break end end tag end # Get all the text between the current position and the next tag # (if specified) or a specific later tag def getText(until_tag = nil) if until_tag.nil? if ?< == @page[@cur_pos] # Next token is a tag, not text "" else # Next token is text getNextToken.text end else ret_str = "" while (tag = peekNextToken) if tag.kind_of?(HTMLTag) and tag.tag_name == until_tag break end if ("" != tag.text) ret_str << (tag.text + " ") end getNextToken end ret_str end end # Like getText, but squeeze all whitespace, getting rid of # leading and trailing whitespace, and squeezing multiple # spaces into a single space. def getTrimmedText(until_tag = nil) getText(until_tag).strip.gsub(/\s+/m, " ") end end class HTMLTokenizerError < Exception end # The parent class for all three types of HTML tokens class HTMLToken attr_accessor :raw # Initialize the token based on the raw text def initialize(text) @raw = text end # By default, return exactly the string used to create the text def to_s raw end # By default tokens have no text representation def text "" end def trimmed_text text.strip.gsub(/\s+/m, " ") end # Compare to another based on the raw source def ==(other) raw == other.to_s end end # Class representing text that isn't inside a tag class HTMLText < HTMLToken def text raw end end # Class representing an HTML comment class HTMLComment < HTMLToken attr_accessor :contents def initialize(text) super(text) temp_arr = text.scan(/^$/m) if temp_arr[0].nil? raise HTMLTokenizerError, "Text passed to HTMLComment.initialize is not a comment" end @contents = temp_arr[0][0] end end # Class representing an HTML tag class HTMLTag < HTMLToken attr_reader :end_tag, :tag_name def initialize(text) super(text) if ?< != text[0] or ?> != text[-1] raise HTMLTokenizerError, "Text passed to HTMLComment.initialize is not a comment" end @attr_hash = Hash.new @raw = text tag_name = text.scan(/[\w:-]+/)[0] if tag_name.nil? raise HTMLTokenizerError, "Error, tag is nil: #{tag_name}" end if ?/ == text[1] # It's an end tag @end_tag = true @tag_name = '/' + tag_name.downcase else @end_tag = false @tag_name = tag_name.downcase end @hashed = false end # Retrieve a hash of all the tag's attributes. # Lazily done, so that if you don't look at a tag's attributes # things go quicker def attr_hash # Lazy initialize == don't build the hash until it's needed if !@hashed if !@end_tag # Get the attributes attr_arr = @raw.scan(/<[\w:-]+\s+(.*?)\/?>/m)[0] if attr_arr.kind_of?(Array) # Attributes found, parse them attrs = attr_arr[0] attr_arr = attrs.scan(/\s*([\w:-]+)(?:\s*=\s*("[^"]*"|'[^']*'|([^"'>][^\s>]*)))?/m) # clean up the array by: # * setting all nil elements to true # * removing enclosing quotes attr_arr.each { |item| val = if item[1].nil? item[0] elsif '"'[0] == item[1][0] or '\''[0] == item[1][0] item[1][1 .. -2] else item[1] end @attr_hash[item[0].downcase] = val } end end @hashed = true end #p self @attr_hash end # Get the 'alt' text for a tag, if it exists, or an empty string otherwise def text if !end_tag case tag_name when 'img' if !attr_hash['alt'].nil? return attr_hash['alt'] end when 'applet' if !attr_hash['alt'].nil? return attr_hash['alt'] end end end return '' end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/discovery.rb0000644000175000017500000001115412512544714023007 0ustar sbadiasbadia require 'openid/util' require 'openid/fetchers' require 'openid/yadis/constants' require 'openid/yadis/parsehtml' module OpenID # Raised when a error occurs in the discovery process class DiscoveryFailure < OpenIDError attr_accessor :identity_url, :http_response def initialize(message, http_response) super(message) @identity_url = nil @http_response = http_response end end module Yadis # Contains the result of performing Yadis discovery on a URI class DiscoveryResult # The result of following redirects from the request_uri attr_accessor :normalize_uri # The URI from which the response text was returned (set to # nil if there was no XRDS document found) attr_accessor :xrds_uri # The content-type returned with the response_text attr_accessor :content_type # The document returned from the xrds_uri attr_accessor :response_text attr_accessor :request_uri, :normalized_uri def initialize(request_uri) # Initialize the state of the object # # sets all attributes to None except the request_uri @request_uri = request_uri @normalized_uri = nil @xrds_uri = nil @content_type = nil @response_text = nil end # Was the Yadis protocol's indirection used? def used_yadis_location? return @normalized_uri != @xrds_uri end # Is the response text supposed to be an XRDS document? def is_xrds return (used_yadis_location?() or @content_type == YADIS_CONTENT_TYPE) end end # Discover services for a given URI. # # uri: The identity URI as a well-formed http or https URI. The # well-formedness and the protocol are not checked, but the # results of this function are undefined if those properties do # not hold. # # returns a DiscoveryResult object # # Raises DiscoveryFailure when the HTTP response does not have # a 200 code. def self.discover(uri) result = DiscoveryResult.new(uri) begin resp = OpenID.fetch(uri, nil, {'Accept' => YADIS_ACCEPT_HEADER}) rescue Exception raise DiscoveryFailure.new("Failed to fetch identity URL #{uri} : #{$!}", $!) end if resp.code != "200" and resp.code != "206" raise DiscoveryFailure.new( "HTTP Response status from identity URL host is not \"200\"."\ "Got status #{resp.code.inspect} for #{resp.final_url}", resp) end # Note the URL after following redirects result.normalized_uri = resp.final_url # Attempt to find out where to go to discover the document or if # we already have it result.content_type = resp['content-type'] result.xrds_uri = self.where_is_yadis?(resp) if result.xrds_uri and result.used_yadis_location? begin resp = OpenID.fetch(result.xrds_uri) rescue raise DiscoveryFailure.new("Failed to fetch Yadis URL #{result.xrds_uri} : #{$!}", $!) end if resp.code != "200" and resp.code != "206" exc = DiscoveryFailure.new( "HTTP Response status from Yadis host is not \"200\". " + "Got status #{resp.code.inspect} for #{resp.final_url}", resp) exc.identity_url = result.normalized_uri raise exc end result.content_type = resp['content-type'] end result.response_text = resp.body return result end # Given a HTTPResponse, return the location of the Yadis # document. # # May be the URL just retrieved, another URL, or None, if I # can't find any. # # [non-blocking] def self.where_is_yadis?(resp) # Attempt to find out where to go to discover the document or if # we already have it content_type = resp['content-type'] # According to the spec, the content-type header must be an # exact match, or else we have to look for an indirection. if (!content_type.nil? and !content_type.to_s.empty? and content_type.split(';', 2)[0].downcase == YADIS_CONTENT_TYPE) return resp.final_url else # Try the header yadis_loc = resp[YADIS_HEADER_NAME.downcase] if yadis_loc.nil? # Parse as HTML if the header is missing. # # XXX: do we want to do something with content-type, like # have a whitelist or a blacklist (for detecting that it's # HTML)? yadis_loc = Yadis.html_yadis_location(resp.body) end end return yadis_loc end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/xrds.rb0000644000175000017500000001003612512544714021756 0ustar sbadiasbadiarequire 'rexml/document' require 'rexml/element' require 'rexml/xpath' require 'openid/yadis/xri' module OpenID module Yadis XRD_NS_2_0 = 'xri://$xrd*($v*2.0)' XRDS_NS = 'xri://$xrds' XRDS_NAMESPACES = { 'xrds' => XRDS_NS, 'xrd' => XRD_NS_2_0, } class XRDSError < StandardError; end # Raised when there's an assertion in the XRDS that it does not # have the authority to make. class XRDSFraud < XRDSError end def Yadis::get_canonical_id(iname, xrd_tree) # Return the CanonicalID from this XRDS document. # # @param iname: the XRI being resolved. # @type iname: unicode # # @param xrd_tree: The XRDS output from the resolver. # # @returns: The XRI CanonicalID or None. # @returntype: unicode or None xrd_list = [] REXML::XPath::match(xrd_tree.root, '/xrds:XRDS/xrd:XRD', XRDS_NAMESPACES).each { |el| xrd_list << el } xrd_list.reverse! cid_elements = [] if !xrd_list.empty? xrd_list[0].elements.each { |e| if !e.respond_to?('name') next end if e.name == 'CanonicalID' cid_elements << e end } end cid_element = cid_elements[0] if !cid_element return nil end canonicalID = XRI.make_xri(cid_element.text) childID = canonicalID.downcase xrd_list[1..-1].each { |xrd| parent_sought = childID[0...childID.rindex('!')] parent = XRI.make_xri(xrd.elements["CanonicalID"].text) if parent_sought != parent.downcase raise XRDSFraud.new(sprintf("%s can not come from %s", parent_sought, parent)) end childID = parent_sought } root = XRI.root_authority(iname) if not XRI.provider_is_authoritative(root, childID) raise XRDSFraud.new(sprintf("%s can not come from root %s", childID, root)) end return canonicalID end class XRDSError < StandardError end def Yadis::parseXRDS(text) disable_entity_expansion do if text.nil? raise XRDSError.new("Not an XRDS document.") end begin d = REXML::Document.new(text) rescue RuntimeError raise XRDSError.new("Not an XRDS document. Failed to parse XML.") end if is_xrds?(d) return d else raise XRDSError.new("Not an XRDS document.") end end end def Yadis::disable_entity_expansion _previous_ = REXML::Document::entity_expansion_limit REXML::Document::entity_expansion_limit = 0 yield ensure REXML::Document::entity_expansion_limit = _previous_ end def Yadis::is_xrds?(xrds_tree) xrds_root = xrds_tree.root return (!xrds_root.nil? and xrds_root.name == 'XRDS' and xrds_root.namespace == XRDS_NS) end def Yadis::get_yadis_xrd(xrds_tree) REXML::XPath.each(xrds_tree.root, '/xrds:XRDS/xrd:XRD[last()]', XRDS_NAMESPACES) { |el| return el } raise XRDSError.new("No XRD element found.") end # aka iterServices in Python def Yadis::each_service(xrds_tree, &block) xrd = get_yadis_xrd(xrds_tree) xrd.each_element('Service', &block) end def Yadis::services(xrds_tree) s = [] each_service(xrds_tree) { |service| s << service } return s end def Yadis::expand_service(service_element) es = service_element.elements uris = es.each('URI') { |u| } uris = prio_sort(uris) types = es.each('Type/text()') # REXML::Text objects are not strings. types = types.collect { |t| t.to_s } uris.collect { |uri| [types, uri.text, service_element] } end # Sort a list of elements that have priority attributes. def Yadis::prio_sort(elements) elements.sort { |a,b| a.attribute('priority').to_s.to_i <=> b.attribute('priority').to_s.to_i } end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/parsehtml.rb0000644000175000017500000000251612512544714023001 0ustar sbadiasbadiarequire "openid/yadis/htmltokenizer" require 'cgi' module OpenID module Yadis def Yadis.html_yadis_location(html) parser = HTMLTokenizer.new(html) # to keep track of whether or not we are in the head element in_head = false begin while el = parser.getTag('head', '/head', 'meta', 'body', '/body', 'html', 'script') # we are leaving head or have reached body, so we bail return nil if ['/head', 'body', '/body'].member?(el.tag_name) if el.tag_name == 'head' unless el.to_s[-2] == ?/ # tag ends with a /: a short tag in_head = true end end next unless in_head if el.tag_name == 'script' unless el.to_s[-2] == ?/ # tag ends with a /: a short tag parser.getTag('/script') end end return nil if el.tag_name == 'html' if el.tag_name == 'meta' and (equiv = el.attr_hash['http-equiv']) if ['x-xrds-location','x-yadis-location'].member?(equiv.downcase) && el.attr_hash.member?('content') return CGI::unescapeHTML(el.attr_hash['content']) end end end rescue HTMLTokenizerError # just stop parsing if there's an error end end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/services.rb0000644000175000017500000000246112512544714022624 0ustar sbadiasbadia require 'openid/yadis/filters' require 'openid/yadis/discovery' require 'openid/yadis/xrds' module OpenID module Yadis def Yadis.get_service_endpoints(input_url, flt=nil) # Perform the Yadis protocol on the input URL and return an # iterable of resulting endpoint objects. # # @param flt: A filter object or something that is convertable # to a filter object (using mkFilter) that will be used to # generate endpoint objects. This defaults to generating # BasicEndpoint objects. result = Yadis.discover(input_url) begin endpoints = Yadis.apply_filter(result.normalized_uri, result.response_text, flt) rescue XRDSError => err raise DiscoveryFailure.new(err.to_s, nil) end return [result.normalized_uri, endpoints] end def Yadis.apply_filter(normalized_uri, xrd_data, flt=nil) # Generate an iterable of endpoint objects given this input data, # presumably from the result of performing the Yadis protocol. flt = Yadis.make_filter(flt) et = Yadis.parseXRDS(xrd_data) endpoints = [] each_service(et) { |service_element| endpoints += flt.get_service_endpoints(normalized_uri, service_element) } return endpoints end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/constants.rb0000644000175000017500000000117012512544714023011 0ustar sbadiasbadia require 'openid/yadis/accept' module OpenID module Yadis YADIS_HEADER_NAME = 'X-XRDS-Location' YADIS_CONTENT_TYPE = 'application/xrds+xml' # A value suitable for using as an accept header when performing # YADIS discovery, unless the application has special requirements YADIS_ACCEPT_HEADER = generate_accept_header( ['text/html', 0.3], ['application/xhtml+xml', 0.5], [YADIS_CONTENT_TYPE, 1.0] ) end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/accept.rb0000644000175000017500000000744212512544714022244 0ustar sbadiasbadiamodule OpenID module Yadis # Generate an accept header value # # [str or (str, float)] -> str def self.generate_accept_header(*elements) parts = [] elements.each { |element| if element.is_a?(String) qs = "1.0" mtype = element else mtype, q = element q = q.to_f if q > 1 or q <= 0 raise ArgumentError.new("Invalid preference factor: #{q}") end qs = sprintf("%0.1f", q) end parts << [qs, mtype] } parts.sort! chunks = [] parts.each { |q, mtype| if q == '1.0' chunks << mtype else chunks << sprintf("%s; q=%s", mtype, q) end } return chunks.join(', ') end def self.parse_accept_header(value) # Parse an accept header, ignoring any accept-extensions # # returns a list of tuples containing main MIME type, MIME # subtype, and quality markdown. # # str -> [(str, str, float)] chunks = value.split(',', -1).collect { |v| v.strip } accept = [] chunks.each { |chunk| parts = chunk.split(";", -1).collect { |s| s.strip } mtype = parts.shift if mtype.index('/').nil? # This is not a MIME type, so ignore the bad data next end main, sub = mtype.split('/', 2) q = nil parts.each { |ext| if !ext.index('=').nil? k, v = ext.split('=', 2) if k == 'q' q = v.to_f end end } q = 1.0 if q.nil? accept << [q, main, sub] } accept.sort! accept.reverse! return accept.collect { |q, main, sub| [main, sub, q] } end def self.match_types(accept_types, have_types) # Given the result of parsing an Accept: header, and the # available MIME types, return the acceptable types with their # quality markdowns. # # For example: # # >>> acceptable = parse_accept_header('text/html, text/plain; q=0.5') # >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg']) # [('text/html', 1.0), ('text/plain', 0.5)] # # Type signature: ([(str, str, float)], [str]) -> [(str, float)] if accept_types.nil? or accept_types == [] # Accept all of them default = 1 else default = 0 end match_main = {} match_sub = {} accept_types.each { |main, sub, q| if main == '*' default = [default, q].max next elsif sub == '*' match_main[main] = [match_main.fetch(main, 0), q].max else match_sub[[main, sub]] = [match_sub.fetch([main, sub], 0), q].max end } accepted_list = [] order_maintainer = 0 have_types.each { |mtype| main, sub = mtype.split('/', 2) if match_sub.member?([main, sub]) q = match_sub[[main, sub]] else q = match_main.fetch(main, default) end if q != 0 accepted_list << [1 - q, order_maintainer, q, mtype] order_maintainer += 1 end } accepted_list.sort! return accepted_list.collect { |_, _, q, mtype| [mtype, q] } end def self.get_acceptable(accept_header, have_types) # Parse the accept header and return a list of available types # in preferred order. If a type is unacceptable, it will not be # in the resulting list. # # This is a convenience wrapper around matchTypes and # parse_accept_header # # (str, [str]) -> [str] accepted = self.parse_accept_header(accept_header) preferred = self.match_types(accepted, have_types) return preferred.collect { |mtype, _| mtype } end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/xri.rb0000644000175000017500000000510012512544714021574 0ustar sbadiasbadiarequire 'openid/yadis/xrds' require 'openid/fetchers' module OpenID module Yadis module XRI # The '(' is for cross-reference authorities, and hopefully has a # matching ')' somewhere. XRI_AUTHORITIES = ["!", "=", "@", "+", "$", "("] def self.identifier_scheme(identifier) if (!identifier.nil? and identifier.length > 0 and (identifier.match('^xri://') or XRI_AUTHORITIES.member?(identifier[0].chr))) return :xri else return :uri end end # Transform an XRI reference to an IRI reference. Note this is # not not idempotent, so do not apply this to an identifier more # than once. XRI Syntax section 2.3.1 def self.to_iri_normal(xri) iri = xri.dup iri.insert(0, 'xri://') if not iri.match('^xri://') return escape_for_iri(iri) end # Note this is not not idempotent, so do not apply this more than # once. XRI Syntax section 2.3.2 def self.escape_for_iri(xri) esc = xri.dup # encode all % esc.gsub!(/%/, '%25') esc.gsub!(/\((.*?)\)/) { |xref_match| xref_match.gsub(/[\/\?\#]/) { |char_match| CGI::escape(char_match) } } return esc end # Transform an XRI reference to a URI reference. Note this is not # not idempotent, so do not apply this to an identifier more than # once. XRI Syntax section 2.3.1 def self.to_uri_normal(xri) return iri_to_uri(to_iri_normal(xri)) end # RFC 3987 section 3.1 def self.iri_to_uri(iri) uri = iri.dup # for char in ucschar or iprivate # convert each char to %HH%HH%HH (as many %HH as octets) return uri end def self.provider_is_authoritative(provider_id, canonical_id) lastbang = canonical_id.rindex('!') return false unless lastbang parent = canonical_id[0...lastbang] return parent == provider_id end def self.root_authority(xri) xri = xri[6..-1] if xri.index('xri://') == 0 authority = xri.split('/', 2)[0] if authority[0].chr == '(' root = authority[0...authority.index(')')+1] elsif XRI_AUTHORITIES.member?(authority[0].chr) root = authority[0].chr else root = authority.split(/[!*]/)[0] end self.make_xri(root) end def self.make_xri(xri) if xri.index('xri://') != 0 xri = 'xri://' + xri end return xri end end end end ruby-openid-2.7.0debian.orig/lib/openid/yadis/filters.rb0000644000175000017500000001523612512544714022455 0ustar sbadiasbadia# This file contains functions and classes used for extracting # endpoint information out of a Yadis XRD file using the REXML # XML parser. # module OpenID module Yadis class BasicServiceEndpoint attr_reader :type_uris, :yadis_url, :uri, :service_element # Generic endpoint object that contains parsed service # information, as well as a reference to the service element # from which it was generated. If there is more than one # xrd:Type or xrd:URI in the xrd:Service, this object represents # just one of those pairs. # # This object can be used as a filter, because it implements # fromBasicServiceEndpoint. # # The simplest kind of filter you can write implements # fromBasicServiceEndpoint, which takes one of these objects. def initialize(yadis_url, type_uris, uri, service_element) @type_uris = type_uris @yadis_url = yadis_url @uri = uri @service_element = service_element end # Query this endpoint to see if it has any of the given type # URIs. This is useful for implementing other endpoint classes # that e.g. need to check for the presence of multiple # versions of a single protocol. def match_types(type_uris) return @type_uris & type_uris end # Trivial transform from a basic endpoint to itself. This # method exists to allow BasicServiceEndpoint to be used as a # filter. # # If you are subclassing this object, re-implement this function. def self.from_basic_service_endpoint(endpoint) return endpoint end # A hack to make both this class and its instances respond to # this message since Ruby doesn't support static methods. def from_basic_service_endpoint(endpoint) return self.class.from_basic_service_endpoint(endpoint) end end # Take a list of basic filters and makes a filter that # transforms the basic filter into a top-level filter. This is # mostly useful for the implementation of make_filter, which # should only be needed for special cases or internal use by # this library. # # This object is useful for creating simple filters for services # that use one URI and are specified by one Type (we expect most # Types will fit this paradigm). # # Creates a BasicServiceEndpoint object and apply the filter # functions to it until one of them returns a value. class TransformFilterMaker attr_reader :filter_procs # Initialize the filter maker's state # # filter_functions are the endpoint transformer # Procs to apply to the basic endpoint. These are called in # turn until one of them does not return nil, and the result # of that transformer is returned. def initialize(filter_procs) @filter_procs = filter_procs end # Returns an array of endpoint objects produced by the # filter procs. def get_service_endpoints(yadis_url, service_element) endpoints = [] # Do an expansion of the service element by xrd:Type and # xrd:URI Yadis::expand_service(service_element).each { |type_uris, uri, _| # Create a basic endpoint object to represent this # yadis_url, Service, Type, URI combination endpoint = BasicServiceEndpoint.new( yadis_url, type_uris, uri, service_element) e = apply_filters(endpoint) if !e.nil? endpoints << e end } return endpoints end def apply_filters(endpoint) # Apply filter procs to an endpoint until one of them returns # non-nil. @filter_procs.each { |filter_proc| e = filter_proc.call(endpoint) if !e.nil? # Once one of the filters has returned an endpoint, do not # apply any more. return e end } return nil end end class CompoundFilter attr_reader :subfilters # Create a new filter that applies a set of filters to an # endpoint and collects their results. def initialize(subfilters) @subfilters = subfilters end # Generate all endpoint objects for all of the subfilters of # this filter and return their concatenation. def get_service_endpoints(yadis_url, service_element) endpoints = [] @subfilters.each { |subfilter| endpoints += subfilter.get_service_endpoints(yadis_url, service_element) } return endpoints end end # Exception raised when something is not able to be turned into a # filter @@filter_type_error = TypeError.new( 'Expected a filter, an endpoint, a callable or a list of any of these.') # Convert a filter-convertable thing into a filter # # parts should be a filter, an endpoint, a callable, or a list of # any of these. def self.make_filter(parts) # Convert the parts into a list, and pass to mk_compound_filter if parts.nil? parts = [BasicServiceEndpoint] end if parts.is_a?(Array) return mk_compound_filter(parts) else return mk_compound_filter([parts]) end end # Create a filter out of a list of filter-like things # # Used by make_filter # # parts should be a list of things that can be passed to make_filter def self.mk_compound_filter(parts) if !parts.respond_to?('each') raise TypeError, "#{parts.inspect} is not iterable" end # Separate into a list of callables and a list of filter objects transformers = [] filters = [] parts.each { |subfilter| if !subfilter.is_a?(Array) # If it's not an iterable if subfilter.respond_to?('get_service_endpoints') # It's a full filter filters << subfilter elsif subfilter.respond_to?('from_basic_service_endpoint') # It's an endpoint object, so put its endpoint conversion # attribute into the list of endpoint transformers transformers << subfilter.method('from_basic_service_endpoint') elsif subfilter.respond_to?('call') # It's a proc, so add it to the list of endpoint # transformers transformers << subfilter else raise @@filter_type_error end else filters << mk_compound_filter(subfilter) end } if transformers.length > 0 filters << TransformFilterMaker.new(transformers) end if filters.length == 1 return filters[0] else return CompoundFilter.new(filters) end end end end ruby-openid-2.7.0debian.orig/lib/openid/util.rb0000644000175000017500000000536212512544714020650 0ustar sbadiasbadiarequire "cgi" require "uri" require "logger" # See OpenID::Consumer or OpenID::Server modules, as well as the store classes module OpenID class AssertionError < Exception end # Exceptions that are raised by the library are subclasses of this # exception type, so if you want to catch all exceptions raised by # the library, you can catch OpenIDError class OpenIDError < StandardError end module Util BASE64_CHARS = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' \ 'abcdefghijklmnopqrstuvwxyz0123456789+/') BASE64_RE = Regexp.compile(" \\A ([#{BASE64_CHARS}]{4})* ([#{BASE64_CHARS}]{2}==| [#{BASE64_CHARS}]{3}=)? \\Z", Regexp::EXTENDED) def Util.assert(value, message=nil) if not value raise AssertionError, message or value end end def Util.to_base64(s) [s].pack('m').gsub("\n", "") end def Util.from_base64(s) without_newlines = s.gsub(/[\r\n]+/, '') if !BASE64_RE.match(without_newlines) raise ArgumentError, "Malformed input: #{s.inspect}" end without_newlines.unpack('m').first end def Util.urlencode(args) a = [] args.each do |key, val| if val.nil? val = '' elsif !!val == val #it's boolean let's convert it to string representation # or else CGI::escape won't like it val = val.to_s end a << (CGI::escape(key) + "=" + CGI::escape(val)) end a.join("&") end def Util.parse_query(qs) query = {} CGI::parse(qs).each {|k,v| query[k] = v[0]} return query end def Util.append_args(url, args) url = url.dup return url if args.length == 0 if args.respond_to?('each_pair') args = args.sort end url << (url.include?("?") ? "&" : "?") url << Util.urlencode(args) end @@logger = Logger.new(STDERR) @@logger.progname = "OpenID" def Util.logger=(logger) @@logger = logger end def Util.logger @@logger end # change the message below to do whatever you like for logging def Util.log(message) logger.info(message) end def Util.auto_submit_html(form, title='OpenID transaction in progress') return " #{title} #{form} " end ESCAPE_TABLE = { '&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => ''' } # Modified from ERb's html_encode def Util.html_encode(str) str.to_s.gsub(/[&<>"']/) {|s| ESCAPE_TABLE[s] } end end end ruby-openid-2.7.0debian.orig/lib/openid/server.rb0000644000175000017500000014333612512544714021205 0ustar sbadiasbadia require 'openid/cryptutil' require 'openid/util' require 'openid/dh' require 'openid/store/nonce' require 'openid/trustroot' require 'openid/association' require 'openid/message' require 'time' module OpenID module Server HTTP_OK = 200 HTTP_REDIRECT = 302 HTTP_ERROR = 400 BROWSER_REQUEST_MODES = ['checkid_setup', 'checkid_immediate'] ENCODE_KVFORM = ['kvform'].freeze ENCODE_URL = ['URL/redirect'].freeze ENCODE_HTML_FORM = ['HTML form'].freeze UNUSED = nil class OpenIDRequest attr_accessor :message, :mode # I represent an incoming OpenID request. # # Attributes: # mode:: The "openid.mode" of this request def initialize @mode = nil @message = nil end def namespace if @message.nil? raise RuntimeError, "Request has no message" else return @message.get_openid_namespace end end end # A request to verify the validity of a previous response. # # See OpenID Specs, Verifying Directly with the OpenID Provider # class CheckAuthRequest < OpenIDRequest # The association handle the response was signed with. attr_accessor :assoc_handle # The message with the signature which wants checking. attr_accessor :signed # An association handle the client is asking about the validity # of. May be nil. attr_accessor :invalidate_handle attr_accessor :sig # Construct me. # # These parameters are assigned directly as class attributes. # # Parameters: # assoc_handle:: the association handle for this request # signed:: The signed message # invalidate_handle:: An association handle that the relying # party is checking to see if it is invalid def initialize(assoc_handle, signed, invalidate_handle=nil) super() @mode = "check_authentication" @required_fields = ["identity", "return_to", "response_nonce"].freeze @sig = nil @assoc_handle = assoc_handle @signed = signed @invalidate_handle = invalidate_handle end # Construct me from an OpenID::Message. def self.from_message(message, op_endpoint=UNUSED) assoc_handle = message.get_arg(OPENID_NS, 'assoc_handle') invalidate_handle = message.get_arg(OPENID_NS, 'invalidate_handle') signed = message.copy() # openid.mode is currently check_authentication because # that's the mode of this request. But the signature # was made on something with a different openid.mode. # http://article.gmane.org/gmane.comp.web.openid.general/537 if signed.has_key?(OPENID_NS, "mode") signed.set_arg(OPENID_NS, "mode", "id_res") end obj = self.new(assoc_handle, signed, invalidate_handle) obj.message = message obj.sig = message.get_arg(OPENID_NS, 'sig') if !obj.assoc_handle or !obj.sig msg = sprintf("%s request missing required parameter from message %s", obj.mode, message) raise ProtocolError.new(message, msg) end return obj end # Respond to this request. # # Given a Signatory, I can check the validity of the signature # and the invalidate_handle. I return a response with an # is_valid (and, if appropriate invalidate_handle) field. def answer(signatory) is_valid = signatory.verify(@assoc_handle, @signed) # Now invalidate that assoc_handle so it this checkAuth # message cannot be replayed. signatory.invalidate(@assoc_handle, true) response = OpenIDResponse.new(self) valid_str = is_valid ? "true" : "false" response.fields.set_arg(OPENID_NS, 'is_valid', valid_str) if @invalidate_handle assoc = signatory.get_association(@invalidate_handle, false) if !assoc response.fields.set_arg( OPENID_NS, 'invalidate_handle', @invalidate_handle) end end return response end def to_s ih = nil if @invalidate_handle ih = sprintf(" invalidate? %s", @invalidate_handle) else ih = "" end s = sprintf("<%s handle: %s sig: %s: signed: %s%s>", self.class, @assoc_handle, @sig, @signed, ih) return s end end class BaseServerSession attr_reader :session_type def initialize(session_type, allowed_assoc_types) @session_type = session_type @allowed_assoc_types = allowed_assoc_types.dup.freeze end def allowed_assoc_type?(typ) @allowed_assoc_types.member?(typ) end end # An object that knows how to handle association requests with # no session type. # # See OpenID Specs, Section 8: Establishing Associations # class PlainTextServerSession < BaseServerSession # The session_type for this association session. There is no # type defined for plain-text in the OpenID specification, so we # use 'no-encryption'. attr_reader :session_type def initialize super('no-encryption', ['HMAC-SHA1', 'HMAC-SHA256']) end def self.from_message(unused_request) return self.new end def answer(secret) return {'mac_key' => Util.to_base64(secret)} end end # An object that knows how to handle association requests with the # Diffie-Hellman session type. # # See OpenID Specs, Section 8: Establishing Associations # class DiffieHellmanSHA1ServerSession < BaseServerSession # The Diffie-Hellman algorithm values for this request attr_accessor :dh # The public key sent by the consumer in the associate request attr_accessor :consumer_pubkey # The session_type for this association session. attr_reader :session_type def initialize(dh, consumer_pubkey) super('DH-SHA1', ['HMAC-SHA1']) @hash_func = CryptUtil.method('sha1') @dh = dh @consumer_pubkey = consumer_pubkey end # Construct me from OpenID Message # # Raises ProtocolError when parameters required to establish the # session are missing. def self.from_message(message) dh_modulus = message.get_arg(OPENID_NS, 'dh_modulus') dh_gen = message.get_arg(OPENID_NS, 'dh_gen') if ((!dh_modulus and dh_gen) or (!dh_gen and dh_modulus)) if !dh_modulus missing = 'modulus' else missing = 'generator' end raise ProtocolError.new(message, sprintf('If non-default modulus or generator is ' + 'supplied, both must be supplied. Missing %s', missing)) end if dh_modulus or dh_gen dh_modulus = CryptUtil.base64_to_num(dh_modulus) dh_gen = CryptUtil.base64_to_num(dh_gen) dh = DiffieHellman.new(dh_modulus, dh_gen) else dh = DiffieHellman.from_defaults() end consumer_pubkey = message.get_arg(OPENID_NS, 'dh_consumer_public') if !consumer_pubkey raise ProtocolError.new(message, sprintf("Public key for DH-SHA1 session " + "not found in message %s", message)) end consumer_pubkey = CryptUtil.base64_to_num(consumer_pubkey) return self.new(dh, consumer_pubkey) end def answer(secret) mac_key = @dh.xor_secret(@hash_func, @consumer_pubkey, secret) return { 'dh_server_public' => CryptUtil.num_to_base64(@dh.public), 'enc_mac_key' => Util.to_base64(mac_key), } end end class DiffieHellmanSHA256ServerSession < DiffieHellmanSHA1ServerSession def initialize(*args) super(*args) @session_type = 'DH-SHA256' @hash_func = CryptUtil.method('sha256') @allowed_assoc_types = ['HMAC-SHA256'].freeze end end # A request to establish an association. # # See OpenID Specs, Section 8: Establishing Associations # class AssociateRequest < OpenIDRequest # An object that knows how to handle association requests of a # certain type. attr_accessor :session # The type of association. Supported values include HMAC-SHA256 # and HMAC-SHA1 attr_accessor :assoc_type @@session_classes = { 'no-encryption' => PlainTextServerSession, 'DH-SHA1' => DiffieHellmanSHA1ServerSession, 'DH-SHA256' => DiffieHellmanSHA256ServerSession, } # Construct me. # # The session is assigned directly as a class attribute. See my # class documentation for its description. def initialize(session, assoc_type) super() @session = session @assoc_type = assoc_type @mode = "associate" end # Construct me from an OpenID Message. def self.from_message(message, op_endpoint=UNUSED) if message.is_openid1() session_type = message.get_arg(OPENID_NS, 'session_type') if session_type == 'no-encryption' Util.log('Received OpenID 1 request with a no-encryption ' + 'association session type. Continuing anyway.') elsif !session_type session_type = 'no-encryption' end else session_type = message.get_arg(OPENID2_NS, 'session_type') if !session_type raise ProtocolError.new(message, "session_type missing from request") end end session_class = @@session_classes[session_type] if !session_class raise ProtocolError.new(message, sprintf("Unknown session type %s", session_type)) end begin session = session_class.from_message(message) rescue ArgumentError => why # XXX raise ProtocolError.new(message, sprintf('Error parsing %s session: %s', session_type, why)) end assoc_type = message.get_arg(OPENID_NS, 'assoc_type', 'HMAC-SHA1') if !session.allowed_assoc_type?(assoc_type) msg = sprintf('Session type %s does not support association type %s', session_type, assoc_type) raise ProtocolError.new(message, msg) end obj = self.new(session, assoc_type) obj.message = message return obj end # Respond to this request with an association. # # assoc:: The association to send back. # # Returns a response with the association information, encrypted # to the consumer's public key if appropriate. def answer(assoc) response = OpenIDResponse.new(self) response.fields.update_args(OPENID_NS, { 'expires_in' => sprintf('%d', assoc.expires_in()), 'assoc_type' => @assoc_type, 'assoc_handle' => assoc.handle, }) response.fields.update_args(OPENID_NS, @session.answer(assoc.secret)) unless (@session.session_type == 'no-encryption' and @message.is_openid1) response.fields.set_arg( OPENID_NS, 'session_type', @session.session_type) end return response end # Respond to this request indicating that the association type # or association session type is not supported. def answer_unsupported(message, preferred_association_type=nil, preferred_session_type=nil) if @message.is_openid1() raise ProtocolError.new(@message) end response = OpenIDResponse.new(self) response.fields.set_arg(OPENID_NS, 'error_code', 'unsupported-type') response.fields.set_arg(OPENID_NS, 'error', message) if preferred_association_type response.fields.set_arg( OPENID_NS, 'assoc_type', preferred_association_type) end if preferred_session_type response.fields.set_arg( OPENID_NS, 'session_type', preferred_session_type) end return response end end # A request to confirm the identity of a user. # # This class handles requests for openid modes # +checkid_immediate+ and +checkid_setup+ . class CheckIDRequest < OpenIDRequest # Provided in smart mode requests, a handle for a previously # established association. nil for dumb mode requests. attr_accessor :assoc_handle # Is this an immediate-mode request? attr_accessor :immediate # The URL to send the user agent back to to reply to this # request. attr_accessor :return_to # The OP-local identifier being checked. attr_accessor :identity # The claimed identifier. Not present in OpenID 1.x # messages. attr_accessor :claimed_id # This URL identifies the party making the request, and the user # will use that to make her decision about what answer she # trusts them to have. Referred to as "realm" in OpenID 2.0. attr_accessor :trust_root # mode:: +checkid_immediate+ or +checkid_setup+ attr_accessor :mode attr_accessor :op_endpoint # These parameters are assigned directly as attributes, # see the #CheckIDRequest class documentation for their # descriptions. # # Raises #MalformedReturnURL when the +return_to+ URL is not # a URL. def initialize(identity, return_to, op_endpoint, trust_root=nil, immediate=false, assoc_handle=nil, claimed_id=nil) @assoc_handle = assoc_handle @identity = identity @claimed_id = (claimed_id or identity) @return_to = return_to @trust_root = (trust_root or return_to) @op_endpoint = op_endpoint @message = nil if immediate @immediate = true @mode = "checkid_immediate" else @immediate = false @mode = "checkid_setup" end if @return_to and !TrustRoot::TrustRoot.parse(@return_to) raise MalformedReturnURL.new(nil, @return_to) end if !trust_root_valid() raise UntrustedReturnURL.new(nil, @return_to, @trust_root) end end # Construct me from an OpenID message. # # message:: An OpenID checkid_* request Message # # op_endpoint:: The endpoint URL of the server that this # message was sent to. # # Raises: # ProtocolError:: When not all required parameters are present # in the message. # # MalformedReturnURL:: When the +return_to+ URL is not a URL. # # UntrustedReturnURL:: When the +return_to+ URL is # outside the +trust_root+. def self.from_message(message, op_endpoint) obj = self.allocate obj.message = message obj.op_endpoint = op_endpoint mode = message.get_arg(OPENID_NS, 'mode') if mode == "checkid_immediate" obj.immediate = true obj.mode = "checkid_immediate" else obj.immediate = false obj.mode = "checkid_setup" end obj.return_to = message.get_arg(OPENID_NS, 'return_to') if message.is_openid1 and !obj.return_to msg = sprintf("Missing required field 'return_to' from %s", message) raise ProtocolError.new(message, msg) end obj.identity = message.get_arg(OPENID_NS, 'identity') obj.claimed_id = message.get_arg(OPENID_NS, 'claimed_id') if message.is_openid1() if !obj.identity s = "OpenID 1 message did not contain openid.identity" raise ProtocolError.new(message, s) end else if obj.identity and not obj.claimed_id s = ("OpenID 2.0 message contained openid.identity but not " + "claimed_id") raise ProtocolError.new(message, s) elsif obj.claimed_id and not obj.identity s = ("OpenID 2.0 message contained openid.claimed_id but not " + "identity") raise ProtocolError.new(message, s) end end # There's a case for making self.trust_root be a TrustRoot # here. But if TrustRoot isn't currently part of the "public" # API, I'm not sure it's worth doing. if message.is_openid1 trust_root_param = 'trust_root' else trust_root_param = 'realm' end trust_root = message.get_arg(OPENID_NS, trust_root_param) trust_root = obj.return_to if (trust_root.nil? || trust_root.empty?) obj.trust_root = trust_root if !message.is_openid1 and !obj.return_to and !obj.trust_root raise ProtocolError.new(message, "openid.realm required when " + "openid.return_to absent") end obj.assoc_handle = message.get_arg(OPENID_NS, 'assoc_handle') # Using TrustRoot.parse here is a bit misleading, as we're not # parsing return_to as a trust root at all. However, valid # URLs are valid trust roots, so we can use this to get an # idea if it is a valid URL. Not all trust roots are valid # return_to URLs, however (particularly ones with wildcards), # so this is still a little sketchy. if obj.return_to and \ !TrustRoot::TrustRoot.parse(obj.return_to) raise MalformedReturnURL.new(message, obj.return_to) end # I first thought that checking to see if the return_to is # within the trust_root is premature here, a # logic-not-decoding thing. But it was argued that this is # really part of data validation. A request with an invalid # trust_root/return_to is broken regardless of application, # right? if !obj.trust_root_valid() raise UntrustedReturnURL.new(message, obj.return_to, obj.trust_root) end return obj end # Is the identifier to be selected by the IDP? def id_select # So IDPs don't have to import the constant return @identity == IDENTIFIER_SELECT end # Is my return_to under my trust_root? def trust_root_valid if !@trust_root return true end tr = TrustRoot::TrustRoot.parse(@trust_root) if !tr raise MalformedTrustRoot.new(@message, @trust_root) end if @return_to return tr.validate_url(@return_to) else return true end end # Does the relying party publish the return_to URL for this # response under the realm? It is up to the provider to set a # policy for what kinds of realms should be allowed. This # return_to URL verification reduces vulnerability to # data-theft attacks based on open proxies, # corss-site-scripting, or open redirectors. # # This check should only be performed after making sure that # the return_to URL matches the realm. # # Raises DiscoveryFailure if the realm # URL does not support Yadis discovery (and so does not # support the verification process). # # Returns true if the realm publishes a document with the # return_to URL listed def return_to_verified return TrustRoot.verify_return_to(@trust_root, @return_to) end # Respond to this request. # # allow:: Allow this user to claim this identity, and allow the # consumer to have this information? # # server_url:: DEPRECATED. Passing op_endpoint to the # #Server constructor makes this optional. # # When an OpenID 1.x immediate mode request does # not succeed, it gets back a URL where the request # may be carried out in a not-so-immediate fashion. # Pass my URL in here (the fully qualified address # of this server's endpoint, i.e. # http://example.com/server), and I will # use it as a base for the URL for a new request. # # Optional for requests where # #CheckIDRequest.immediate is false or +allow+ is # true. # # identity:: The OP-local identifier to answer with. Only for use # when the relying party requested identifier selection. # # claimed_id:: The claimed identifier to answer with, # for use with identifier selection in the case where the # claimed identifier and the OP-local identifier differ, # i.e. when the claimed_id uses delegation. # # If +identity+ is provided but this is not, # +claimed_id+ will default to the value of +identity+. # When answering requests that did not ask for identifier # selection, the response +claimed_id+ will default to # that of the request. # # This parameter is new in OpenID 2.0. # # Returns an OpenIDResponse object containing a OpenID id_res message. # # Raises NoReturnToError if the return_to is missing. # # Version 2.0 deprecates +server_url+ and adds +claimed_id+. def answer(allow, server_url=nil, identity=nil, claimed_id=nil) if !@return_to raise NoReturnToError end if !server_url if @message.is_openid2 and !@op_endpoint # In other words, that warning I raised in # Server.__init__? You should pay attention to it now. raise RuntimeError, ("#{self} should be constructed with "\ "op_endpoint to respond to OpenID 2.0 "\ "messages.") end server_url = @op_endpoint end if allow mode = 'id_res' elsif @message.is_openid1 if @immediate mode = 'id_res' else mode = 'cancel' end else if @immediate mode = 'setup_needed' else mode = 'cancel' end end response = OpenIDResponse.new(self) if claimed_id and @message.is_openid1 raise VersionError, ("claimed_id is new in OpenID 2.0 and not "\ "available for #{@message.get_openid_namespace}") end if identity and !claimed_id claimed_id = identity end if allow if @identity == IDENTIFIER_SELECT if !identity raise ArgumentError, ("This request uses IdP-driven "\ "identifier selection.You must supply "\ "an identifier in the response.") end response_identity = identity response_claimed_id = claimed_id elsif @identity if identity and (@identity != identity) raise ArgumentError, ("Request was for identity #{@identity}, "\ "cannot reply with identity #{identity}") end response_identity = @identity response_claimed_id = @claimed_id else if identity raise ArgumentError, ("This request specified no identity "\ "and you supplied #{identity}") end response_identity = nil end if @message.is_openid1 and !response_identity raise ArgumentError, ("Request was an OpenID 1 request, so "\ "response must include an identifier.") end response.fields.update_args(OPENID_NS, { 'mode' => mode, 'op_endpoint' => server_url, 'return_to' => @return_to, 'response_nonce' => Nonce.mk_nonce(), }) if response_identity response.fields.set_arg(OPENID_NS, 'identity', response_identity) if @message.is_openid2 response.fields.set_arg(OPENID_NS, 'claimed_id', response_claimed_id) end end else response.fields.set_arg(OPENID_NS, 'mode', mode) if @immediate if @message.is_openid1 and !server_url raise ArgumentError, ("setup_url is required for allow=false "\ "in OpenID 1.x immediate mode.") end # Make a new request just like me, but with # immediate=false. setup_request = self.class.new(@identity, @return_to, @op_endpoint, @trust_root, false, @assoc_handle, @claimed_id) setup_request.message = Message.new(@message.get_openid_namespace) setup_url = setup_request.encode_to_url(server_url) response.fields.set_arg(OPENID_NS, 'user_setup_url', setup_url) end end return response end def encode_to_url(server_url) # Encode this request as a URL to GET. # # server_url:: The URL of the OpenID server to make this # request of. if !@return_to raise NoReturnToError end # Imported from the alternate reality where these classes are # used in both the client and server code, so Requests are # Encodable too. That's right, code imported from alternate # realities all for the love of you, id_res/user_setup_url. q = {'mode' => @mode, 'identity' => @identity, 'claimed_id' => @claimed_id, 'return_to' => @return_to} if @trust_root if @message.is_openid1 q['trust_root'] = @trust_root else q['realm'] = @trust_root end end if @assoc_handle q['assoc_handle'] = @assoc_handle end response = Message.new(@message.get_openid_namespace) response.update_args(@message.get_openid_namespace, q) return response.to_url(server_url) end def cancel_url # Get the URL to cancel this request. # # Useful for creating a "Cancel" button on a web form so that # operation can be carried out directly without another trip # through the server. # # (Except you may want to make another trip through the # server so that it knows that the user did make a decision.) # # Returns a URL as a string. if !@return_to raise NoReturnToError end if @immediate raise ArgumentError.new("Cancel is not an appropriate response to " + "immediate mode requests.") end response = Message.new(@message.get_openid_namespace) response.set_arg(OPENID_NS, 'mode', 'cancel') return response.to_url(@return_to) end def to_s return sprintf('<%s id:%s im:%s tr:%s ah:%s>', self.class, @identity, @immediate, @trust_root, @assoc_handle) end end # I am a response to an OpenID request. # # Attributes: # signed:: A list of the names of the fields which should be signed. # # Implementer's note: In a more symmetric client/server # implementation, there would be more types of #OpenIDResponse # object and they would have validated attributes according to # the type of response. But as it is, Response objects in a # server are basically write-only, their only job is to go out # over the wire, so this is just a loose wrapper around # #OpenIDResponse.fields. class OpenIDResponse # The #OpenIDRequest I respond to. attr_accessor :request # An #OpenID::Message with the data to be returned. # Keys are parameter names with no # leading openid. e.g. identity and mac_key # never openid.identity. attr_accessor :fields def initialize(request) # Make a response to an OpenIDRequest. @request = request @fields = Message.new(request.namespace) end def to_s return sprintf("%s for %s: %s", self.class, @request.class, @fields) end # form_tag_attrs is a hash of attributes to be added to the form # tag. 'accept-charset' and 'enctype' have defaults that can be # overridden. If a value is supplied for 'action' or 'method', # it will be replaced. # Returns the form markup for this response. def to_form_markup(form_tag_attrs=nil) return @fields.to_form_markup(@request.return_to, form_tag_attrs) end # Wraps the form tag from to_form_markup in a complete HTML document # that uses javascript to autosubmit the form. def to_html(form_tag_attrs=nil) return Util.auto_submit_html(to_form_markup(form_tag_attrs)) end def render_as_form # Returns true if this response's encoding is # ENCODE_HTML_FORM. Convenience method for server authors. return self.which_encoding == ENCODE_HTML_FORM end def needs_signing # Does this response require signing? return @fields.get_arg(OPENID_NS, 'mode') == 'id_res' end # implements IEncodable def which_encoding # How should I be encoded? # returns one of ENCODE_URL or ENCODE_KVFORM. if BROWSER_REQUEST_MODES.member?(@request.mode) if @fields.is_openid2 and encode_to_url.length > OPENID1_URL_LIMIT return ENCODE_HTML_FORM else return ENCODE_URL end else return ENCODE_KVFORM end end def encode_to_url # Encode a response as a URL for the user agent to GET. # You will generally use this URL with a HTTP redirect. return @fields.to_url(@request.return_to) end def add_extension(extension_response) # Add an extension response to this response message. # # extension_response:: An object that implements the # #OpenID::Extension interface for adding arguments to an OpenID # message. extension_response.to_message(@fields) end def encode_to_kvform # Encode a response in key-value colon/newline format. # # This is a machine-readable format used to respond to # messages which came directly from the consumer and not # through the user agent. # # see: OpenID Specs, # Key-Value Colon/Newline format return @fields.to_kvform end def copy return Marshal.load(Marshal.dump(self)) end end # I am a response to an OpenID request in terms a web server # understands. # # I generally come from an #Encoder, either directly or from # #Server.encodeResponse. class WebResponse # The HTTP code of this response as an integer. attr_accessor :code # #Hash of headers to include in this response. attr_accessor :headers # The body of this response. attr_accessor :body def initialize(code=HTTP_OK, headers=nil, body="") # Construct me. # # These parameters are assigned directly as class attributes, # see my class documentation for their # descriptions. @code = code if headers @headers = headers else @headers = {} end @body = body end end # I sign things. # # I also check signatures. # # All my state is encapsulated in a store, which means I'm not # generally pickleable but I am easy to reconstruct. class Signatory # The number of seconds a secret remains valid. Defaults to 14 days. attr_accessor :secret_lifetime # keys have a bogus server URL in them because the filestore # really does expect that key to be a URL. This seems a little # silly for the server store, since I expect there to be only # one server URL. @@_normal_key = 'http://localhost/|normal' @@_dumb_key = 'http://localhost/|dumb' def self._normal_key @@_normal_key end def self._dumb_key @@_dumb_key end attr_accessor :store # Create a new Signatory. store is The back-end where my # associations are stored. def initialize(store) Util.assert(store) @store = store @secret_lifetime = 14 * 24 * 60 * 60 end # Verify that the signature for some data is valid. def verify(assoc_handle, message) assoc = get_association(assoc_handle, true) if !assoc Util.log(sprintf("failed to get assoc with handle %s to verify " + "message %s", assoc_handle, message)) return false end begin valid = assoc.check_message_signature(message) rescue StandardError => ex Util.log(sprintf("Error in verifying %s with %s: %s", message, assoc, ex)) return false end return valid end # Sign a response. # # I take an OpenIDResponse, create a signature for everything in # its signed list, and return a new copy of the response object # with that signature included. def sign(response) signed_response = response.copy assoc_handle = response.request.assoc_handle if assoc_handle # normal mode disabling expiration check because even if the # association is expired, we still need to know some # properties of the association so that we may preserve # those properties when creating the fallback association. assoc = get_association(assoc_handle, false, false) if !assoc or assoc.expires_in <= 0 # fall back to dumb mode signed_response.fields.set_arg( OPENID_NS, 'invalidate_handle', assoc_handle) assoc_type = assoc ? assoc.assoc_type : 'HMAC-SHA1' if assoc and assoc.expires_in <= 0 # now do the clean-up that the disabled checkExpiration # code didn't get to do. invalidate(assoc_handle, false) end assoc = create_association(true, assoc_type) end else # dumb mode. assoc = create_association(true) end begin signed_response.fields = assoc.sign_message(signed_response.fields) rescue KVFormError => err raise EncodingError, err end return signed_response end # Make a new association. def create_association(dumb=true, assoc_type='HMAC-SHA1') secret = CryptUtil.random_string(OpenID.get_secret_size(assoc_type)) uniq = Util.to_base64(CryptUtil.random_string(4)) handle = sprintf('{%s}{%x}{%s}', assoc_type, Time.now.to_i, uniq) assoc = Association.from_expires_in( secret_lifetime, handle, secret, assoc_type) if dumb key = @@_dumb_key else key = @@_normal_key end @store.store_association(key, assoc) return assoc end # Get the association with the specified handle. def get_association(assoc_handle, dumb, checkExpiration=true) # Hmm. We've created an interface that deals almost entirely # with assoc_handles. The only place outside the Signatory # that uses this (and thus the only place that ever sees # Association objects) is when creating a response to an # association request, as it must have the association's # secret. if !assoc_handle raise ArgumentError.new("assoc_handle must not be None") end if dumb key = @@_dumb_key else key = @@_normal_key end assoc = @store.get_association(key, assoc_handle) if assoc and assoc.expires_in <= 0 Util.log(sprintf("requested %sdumb key %s is expired (by %s seconds)", (!dumb) ? 'not-' : '', assoc_handle, assoc.expires_in)) if checkExpiration @store.remove_association(key, assoc_handle) assoc = nil end end return assoc end # Invalidates the association with the given handle. def invalidate(assoc_handle, dumb) if dumb key = @@_dumb_key else key = @@_normal_key end @store.remove_association(key, assoc_handle) end end # I encode responses in to WebResponses. # # If you don't like WebResponses, you can do # your own handling of OpenIDResponses with # OpenIDResponse.whichEncoding, # OpenIDResponse.encodeToURL, and # OpenIDResponse.encodeToKVForm. class Encoder @@responseFactory = WebResponse # Encode a response to a WebResponse. # # Raises EncodingError when I can't figure out how to encode # this message. def encode(response) encode_as = response.which_encoding() if encode_as == ENCODE_KVFORM wr = @@responseFactory.new(HTTP_OK, nil, response.encode_to_kvform()) if response.is_a?(Exception) wr.code = HTTP_ERROR end elsif encode_as == ENCODE_URL location = response.encode_to_url() wr = @@responseFactory.new(HTTP_REDIRECT, {'location' => location}) elsif encode_as == ENCODE_HTML_FORM wr = @@responseFactory.new(HTTP_OK, nil, response.to_form_markup()) else # Can't encode this to a protocol message. You should # probably render it to HTML and show it to the user. raise EncodingError.new(response) end return wr end end # I encode responses in to WebResponses, signing # them when required. class SigningEncoder < Encoder attr_accessor :signatory # Create a SigningEncoder given a Signatory def initialize(signatory) @signatory = signatory end # Encode a response to a WebResponse, signing it first if # appropriate. # # Raises EncodingError when I can't figure out how to encode this # message. # # Raises AlreadySigned when this response is already signed. def encode(response) # the is_a? is a bit of a kludge... it means there isn't # really an adapter to make the interfaces quite match. if !response.is_a?(Exception) and response.needs_signing() if !@signatory raise ArgumentError.new( sprintf("Must have a store to sign this request: %s", response), response) end if response.fields.has_key?(OPENID_NS, 'sig') raise AlreadySigned.new(response) end response = @signatory.sign(response) end return super(response) end end # I decode an incoming web request in to a OpenIDRequest. class Decoder @@handlers = { 'checkid_setup' => CheckIDRequest.method('from_message'), 'checkid_immediate' => CheckIDRequest.method('from_message'), 'check_authentication' => CheckAuthRequest.method('from_message'), 'associate' => AssociateRequest.method('from_message'), } attr_accessor :server # Construct a Decoder. The server is necessary because some # replies reference their server. def initialize(server) @server = server end # I transform query parameters into an OpenIDRequest. # # If the query does not seem to be an OpenID request at all, I # return nil. # # Raises ProtocolError when the query does not seem to be a valid # OpenID request. def decode(query) if query.nil? or query.length == 0 return nil end begin message = Message.from_post_args(query) rescue InvalidOpenIDNamespace => e query = query.dup query['openid.ns'] = OPENID2_NS message = Message.from_post_args(query) raise ProtocolError.new(message, e.to_s) end mode = message.get_arg(OPENID_NS, 'mode') if !mode msg = sprintf("No mode value in message %s", message) raise ProtocolError.new(message, msg) end handler = @@handlers.fetch(mode, self.method('default_decoder')) return handler.call(message, @server.op_endpoint) end # Called to decode queries when no handler for that mode is # found. # # This implementation always raises ProtocolError. def default_decoder(message, server) mode = message.get_arg(OPENID_NS, 'mode') msg = sprintf("Unrecognized OpenID mode %s", mode) raise ProtocolError.new(message, msg) end end # I handle requests for an OpenID server. # # Some types of requests (those which are not checkid requests) # may be handed to my handleRequest method, and I will take care # of it and return a response. # # For your convenience, I also provide an interface to # Decoder.decode and SigningEncoder.encode through my methods # decodeRequest and encodeResponse. # # All my state is encapsulated in an store, which means I'm not # generally pickleable but I am easy to reconstruct. class Server @@signatoryClass = Signatory @@encoderClass = SigningEncoder @@decoderClass = Decoder # The back-end where my associations and nonces are stored. attr_accessor :store # I'm using this for associate requests and to sign things. attr_accessor :signatory # I'm using this to encode things. attr_accessor :encoder # I'm using this to decode things. attr_accessor :decoder # I use this instance of OpenID::AssociationNegotiator to # determine which kinds of associations I can make and how. attr_accessor :negotiator # My URL. attr_accessor :op_endpoint # op_endpoint is new in library version 2.0. def initialize(store, op_endpoint) @store = store @signatory = @@signatoryClass.new(@store) @encoder = @@encoderClass.new(@signatory) @decoder = @@decoderClass.new(self) @negotiator = DefaultNegotiator.copy() @op_endpoint = op_endpoint end # Handle a request. # # Give me a request, I will give you a response. Unless it's a # type of request I cannot handle myself, in which case I will # raise RuntimeError. In that case, you can handle it yourself, # or add a method to me for handling that request type. def handle_request(request) begin handler = self.method('openid_' + request.mode) rescue NameError raise RuntimeError.new( sprintf("%s has no handler for a request of mode %s.", self, request.mode)) end return handler.call(request) end # Handle and respond to check_authentication requests. def openid_check_authentication(request) return request.answer(@signatory) end # Handle and respond to associate requests. def openid_associate(request) assoc_type = request.assoc_type session_type = request.session.session_type if @negotiator.allowed?(assoc_type, session_type) assoc = @signatory.create_association(false, assoc_type) return request.answer(assoc) else message = sprintf('Association type %s is not supported with ' + 'session type %s', assoc_type, session_type) preferred_assoc_type, preferred_session_type = @negotiator.get_allowed_type() return request.answer_unsupported(message, preferred_assoc_type, preferred_session_type) end end # Transform query parameters into an OpenIDRequest. # query should contain the query parameters as a Hash with # each key mapping to one value. # # If the query does not seem to be an OpenID request at all, I # return nil. def decode_request(query) return @decoder.decode(query) end # Encode a response to a WebResponse, signing it first if # appropriate. # # Raises EncodingError when I can't figure out how to encode this # message. # # Raises AlreadySigned When this response is already signed. def encode_response(response) return @encoder.encode(response) end end # A message did not conform to the OpenID protocol. class ProtocolError < Exception # The query that is failing to be a valid OpenID request. attr_accessor :openid_message attr_accessor :reference attr_accessor :contact # text:: A message about the encountered error. def initialize(message, text=nil, reference=nil, contact=nil) @openid_message = message @reference = reference @contact = contact Util.assert(!message.is_a?(String)) super(text) end # Get the return_to argument from the request, if any. def get_return_to if @openid_message.nil? return nil else return @openid_message.get_arg(OPENID_NS, 'return_to') end end # Did this request have a return_to parameter? def has_return_to return !get_return_to.nil? end # Generate a Message object for sending to the relying party, # after encoding. def to_message namespace = @openid_message.get_openid_namespace() reply = Message.new(namespace) reply.set_arg(OPENID_NS, 'mode', 'error') reply.set_arg(OPENID_NS, 'error', self.to_s) if @contact reply.set_arg(OPENID_NS, 'contact', @contact.to_s) end if @reference reply.set_arg(OPENID_NS, 'reference', @reference.to_s) end return reply end # implements IEncodable def encode_to_url return to_message().to_url(get_return_to()) end def encode_to_kvform return to_message().to_kvform() end def to_form_markup return to_message().to_form_markup(get_return_to()) end def to_html return Util.auto_submit_html(to_form_markup) end # How should I be encoded? # # Returns one of ENCODE_URL, ENCODE_KVFORM, or None. If None, # I cannot be encoded as a protocol message and should be # displayed to the user. def which_encoding if has_return_to() if @openid_message.is_openid2 and encode_to_url().length > OPENID1_URL_LIMIT return ENCODE_HTML_FORM else return ENCODE_URL end end if @openid_message.nil? return nil end mode = @openid_message.get_arg(OPENID_NS, 'mode') if mode if !BROWSER_REQUEST_MODES.member?(mode) return ENCODE_KVFORM end end # If your request was so broken that you didn't manage to # include an openid.mode, I'm not going to worry too much # about returning you something you can't parse. return nil end end # Raised when an operation was attempted that is not compatible # with the protocol version being used. class VersionError < Exception end # Raised when a response to a request cannot be generated # because the request contains no return_to URL. class NoReturnToError < Exception end # Could not encode this as a protocol message. # # You should probably render it and show it to the user. class EncodingError < Exception # The response that failed to encode. attr_reader :response def initialize(response) super(response) @response = response end end # This response is already signed. class AlreadySigned < EncodingError end # A return_to is outside the trust_root. class UntrustedReturnURL < ProtocolError attr_reader :return_to, :trust_root def initialize(message, return_to, trust_root) super(message) @return_to = return_to @trust_root = trust_root end def to_s return sprintf("return_to %s not under trust_root %s", @return_to, @trust_root) end end # The return_to URL doesn't look like a valid URL. class MalformedReturnURL < ProtocolError attr_reader :return_to def initialize(openid_message, return_to) @return_to = return_to super(openid_message) end end # The trust root is not well-formed. class MalformedTrustRoot < ProtocolError end end end ruby-openid-2.7.0debian.orig/lib/openid/urinorm.rb0000644000175000017500000000342612512544714021365 0ustar sbadiasbadiarequire 'uri' module OpenID module URINorm public def URINorm.urinorm(uri) uri = URI.parse(uri) raise URI::InvalidURIError.new('no scheme') unless uri.scheme uri.scheme = uri.scheme.downcase unless ['http','https'].member?(uri.scheme) raise URI::InvalidURIError.new('Not an HTTP or HTTPS URI') end raise URI::InvalidURIError.new('no host') unless uri.host uri.host = uri.host.downcase uri.path = remove_dot_segments(uri.path) uri.path = '/' if uri.path.length == 0 uri = uri.normalize.to_s uri = uri.gsub(PERCENT_ESCAPE_RE) { sub = $&[1..2].to_i(16).chr reserved(sub) ? $&.upcase : sub } return uri end private RESERVED_RE = /[A-Za-z0-9._~-]/ PERCENT_ESCAPE_RE = /%[0-9a-zA-Z]{2}/ def URINorm.reserved(chr) not RESERVED_RE =~ chr end def URINorm.remove_dot_segments(path) result_segments = [] while path.length > 0 if path.start_with?('../') path = path[3..-1] elsif path.start_with?('./') path = path[2..-1] elsif path.start_with?('/./') path = path[2..-1] elsif path == '/.' path = '/' elsif path.start_with?('/../') path = path[3..-1] result_segments.pop if result_segments.length > 0 elsif path == '/..' path = '/' result_segments.pop if result_segments.length > 0 elsif path == '..' or path == '.' path = '' else i = 0 i = 1 if path[0].chr == '/' i = path.index('/', i) i = path.length if i.nil? result_segments << path[0...i] path = path[i..-1] end end return result_segments.join('') end end end ruby-openid-2.7.0debian.orig/lib/openid/version.rb0000644000175000017500000000004612512544714021352 0ustar sbadiasbadiamodule OpenID VERSION = "2.7.0" end ruby-openid-2.7.0debian.orig/lib/openid/consumer.rb0000644000175000017500000003720112512544714021523 0ustar sbadiasbadiarequire "openid/consumer/idres.rb" require "openid/consumer/checkid_request.rb" require "openid/consumer/associationmanager.rb" require "openid/consumer/responses.rb" require "openid/consumer/session" require "openid/consumer/discovery_manager" require "openid/consumer/discovery" require "openid/message" require "openid/yadis/discovery" require "openid/store/nonce" module OpenID # OpenID support for Relying Parties (aka Consumers). # # This module documents the main interface with the OpenID consumer # library. The only part of the library which has to be used and # isn't documented in full here is the store required to create an # Consumer instance. # # = OVERVIEW # # The OpenID identity verification process most commonly uses the # following steps, as visible to the user of this library: # # 1. The user enters their OpenID into a field on the consumer's # site, and hits a login button. # # 2. The consumer site discovers the user's OpenID provider using # the Yadis protocol. # # 3. The consumer site sends the browser a redirect to the OpenID # provider. This is the authentication request as described in # the OpenID specification. # # 4. The OpenID provider's site sends the browser a redirect back to # the consumer site. This redirect contains the provider's # response to the authentication request. # # The most important part of the flow to note is the consumer's site # must handle two separate HTTP requests in order to perform the # full identity check. # # = LIBRARY DESIGN # # This consumer library is designed with that flow in mind. The # goal is to make it as easy as possible to perform the above steps # securely. # # At a high level, there are two important parts in the consumer # library. The first important part is this module, which contains # the interface to actually use this library. The second is # openid/store/interface.rb, which describes the interface to use if # you need to create a custom method for storing the state this # library needs to maintain between requests. # # In general, the second part is less important for users of the # library to know about, as several implementations are provided # which cover a wide variety of situations in which consumers may # use the library. # # The Consumer class has methods corresponding to the actions # necessary in each of steps 2, 3, and 4 described in the overview. # Use of this library should be as easy as creating an Consumer # instance and calling the methods appropriate for the action the # site wants to take. # # This library automatically detects which version of the OpenID # protocol should be used for a transaction and constructs the # proper requests and responses. Users of this library do not need # to worry about supporting multiple protocol versions; the library # supports them implicitly. Depending on the version of the # protocol in use, the OpenID transaction may be more secure. See # the OpenID specifications for more information. # # = SESSIONS, STORES, AND STATELESS MODE # # The Consumer object keeps track of two types of state: # # 1. State of the user's current authentication attempt. Things # like the identity URL, the list of endpoints discovered for # that URL, and in case where some endpoints are unreachable, the # list of endpoints already tried. This state needs to be held # from Consumer.begin() to Consumer.complete(), but it is only # applicable to a single session with a single user agent, and at # the end of the authentication process (i.e. when an OP replies # with either id_res. or cancel it may be # discarded. # # 2. State of relationships with servers, i.e. shared secrets # (associations) with servers and nonces seen on signed messages. # This information should persist from one session to the next # and should not be bound to a particular user-agent. # # These two types of storage are reflected in the first two # arguments of Consumer's constructor, session and # store. session is a dict-like object and we # hope your web framework provides you with one of these bound to # the user agent. store is an instance of Store. # # Since the store does hold secrets shared between your application # and the OpenID provider, you should be careful about how you use # it in a shared hosting environment. If the filesystem or database # permissions of your web host allow strangers to read from them, do # not store your data there! If you have no safe place to store # your data, construct your consumer with nil for the store, and it # will operate only in stateless mode. Stateless mode may be # slower, put more load on the OpenID provider, and trusts the # provider to keep you safe from replay attacks. # # Several store implementation are provided, and the interface is # fully documented so that custom stores can be used as well. See # the documentation for the Consumer class for more information on # the interface for stores. The implementations that are provided # allow the consumer site to store the necessary data in several # different ways, including several SQL databases and normal files # on disk. # # = IMMEDIATE MODE # # In the flow described above, the user may need to confirm to the # OpenID provider that it's ok to disclose his or her identity. The # provider may draw pages asking for information from the user # before it redirects the browser back to the consumer's site. This # is generally transparent to the consumer site, so it is typically # ignored as an implementation detail. # # There can be times, however, where the consumer site wants to get # a response immediately. When this is the case, the consumer can # put the library in immediate mode. In immediate mode, there is an # extra response possible from the server, which is essentially the # server reporting that it doesn't have enough information to answer # the question yet. # # = USING THIS LIBRARY # # Integrating this library into an application is usually a # relatively straightforward process. The process should basically # follow this plan: # # Add an OpenID login field somewhere on your site. When an OpenID # is entered in that field and the form is submitted, it should make # a request to the your site which includes that OpenID URL. # # First, the application should instantiate a Consumer with a # session for per-user state and store for shared state using the # store of choice. # # Next, the application should call the begin method of # Consumer instance. This method takes the OpenID URL as entered by # the user. The begin method returns a CheckIDRequest # object. # # Next, the application should call the redirect_url method on the # CheckIDRequest object. The parameter return_to is the # URL that the OpenID server will send the user back to after # attempting to verify his or her identity. The realm # parameter is the URL (or URL pattern) that identifies your web # site to the user when he or she is authorizing it. Send a # redirect to the resulting URL to the user's browser. # # That's the first half of the authentication process. The second # half of the process is done after the user's OpenID Provider sends # the user's browser a redirect back to your site to complete their # login. # # When that happens, the user will contact your site at the URL # given as the return_to URL to the redirect_url call made # above. The request will have several query parameters added to # the URL by the OpenID provider as the information necessary to # finish the request. # # Get a Consumer instance with the same session and store as before # and call its complete() method, passing in all the received query # arguments and URL currently being handled. # # There are multiple possible return types possible from that # method. These indicate the whether or not the login was # successful, and include any additional information appropriate for # their type. class Consumer attr_accessor :session_key_prefix # Initialize a Consumer instance. # # You should create a new instance of the Consumer object with # every HTTP request that handles OpenID transactions. # # session: the session object to use to store request information. # The session should behave like a hash. # # store: an object that implements the interface in Store. def initialize(session, store) @origin_session = session @session = Session.new(session, OpenID::OpenIDServiceEndpoint) @store = store @session_key_prefix = 'OpenID::Consumer::' end # Start the OpenID authentication process. See steps 1-2 in the # overview for the Consumer class. # # user_url: Identity URL given by the user. This method performs a # textual transformation of the URL to try and make sure it is # normalized. For example, a user_url of example.com will be # normalized to http://example.com/ normalizing and resolving any # redirects the server might issue. # # anonymous: A boolean value. Whether to make an anonymous # request of the OpenID provider. Such a request does not ask for # an authorization assertion for an OpenID identifier, but may be # used with extensions to pass other data. e.g. "I don't care who # you are, but I'd like to know your time zone." # # Returns a CheckIDRequest object containing the discovered # information, with a method for building a redirect URL to the # server, as described in step 3 of the overview. This object may # also be used to add extension arguments to the request, using # its add_extension_arg method. # # Raises DiscoveryFailure when no OpenID server can be found for # this URL. def begin(openid_identifier, anonymous=false) manager = discovery_manager(openid_identifier) service = manager.get_next_service(&method(:discover)) if service.nil? raise DiscoveryFailure.new("No usable OpenID services were found "\ "for #{openid_identifier.inspect}", nil) else begin_without_discovery(service, anonymous) end end # Start OpenID verification without doing OpenID server # discovery. This method is used internally by Consumer.begin() # after discovery is performed, and exists to provide an interface # for library users needing to perform their own discovery. # # service: an OpenID service endpoint descriptor. This object and # factories for it are found in the openid/consumer/discovery.rb # module. # # Returns an OpenID authentication request object. def begin_without_discovery(service, anonymous) assoc = association_manager(service).get_association checkid_request = CheckIDRequest.new(assoc, service) checkid_request.anonymous = anonymous if service.compatibility_mode rt_args = checkid_request.return_to_args rt_args[Consumer.openid1_return_to_nonce_name] = Nonce.mk_nonce rt_args[Consumer.openid1_return_to_claimed_id_name] = service.claimed_id end self.last_requested_endpoint = service return checkid_request end # Called to interpret the server's response to an OpenID # request. It is called in step 4 of the flow described in the # Consumer overview. # # query: A hash of the query parameters for this HTTP request. # Note that in rails, this is not params but # params.reject{|k,v|request.path_parameters[k]} # because controller and action and other # "path parameters" are included in params. # # current_url: Extract the URL of the current request from your # application's web request framework and specify it here to have it # checked against the openid.return_to value in the response. Do not # just pass args['openid.return_to'] here; that will defeat the # purpose of this check. (See OpenID Authentication 2.0 section 11.1.) # # If the return_to URL check fails, the status of the completion will be # FAILURE. # # Returns a subclass of Response. The type of response is # indicated by the status attribute, which will be one of # SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED. def complete(query, current_url) message = Message.from_post_args(query) mode = message.get_arg(OPENID_NS, 'mode', 'invalid') begin meth = method('complete_' + mode) rescue NameError meth = method(:complete_invalid) end response = meth.call(message, current_url) cleanup_last_requested_endpoint if [SUCCESS, CANCEL].member?(response.status) cleanup_session end return response end protected def session_get(name) @session[session_key(name)] end def session_set(name, val) @session[session_key(name)] = val end def session_key(suffix) @session_key_prefix + suffix end def last_requested_endpoint session_get('last_requested_endpoint') end def last_requested_endpoint=(endpoint) session_set('last_requested_endpoint', endpoint) end def cleanup_last_requested_endpoint @session[session_key('last_requested_endpoint')] = nil end def discovery_manager(openid_identifier) DiscoveryManager.new(@origin_session, openid_identifier, @session_key_prefix) end def cleanup_session discovery_manager(nil).cleanup(true) end def discover(identifier) OpenID.discover(identifier) end def negotiator DefaultNegotiator end def association_manager(service) AssociationManager.new(@store, service.server_url, service.compatibility_mode, negotiator) end def handle_idres(message, current_url) IdResHandler.new(message, current_url, @store, last_requested_endpoint) end def complete_invalid(message, unused_return_to) mode = message.get_arg(OPENID_NS, 'mode', '') return FailureResponse.new(last_requested_endpoint, "Invalid openid.mode: #{mode}") end def complete_cancel(unused_message, unused_return_to) return CancelResponse.new(last_requested_endpoint) end def complete_error(message, unused_return_to) error = message.get_arg(OPENID_NS, 'error') contact = message.get_arg(OPENID_NS, 'contact') reference = message.get_arg(OPENID_NS, 'reference') return FailureResponse.new(last_requested_endpoint, error, contact, reference) end def complete_setup_needed(message, unused_return_to) if message.is_openid1 return complete_invalid(message, nil) else setup_url = message.get_arg(OPENID2_NS, 'user_setup_url') return SetupNeededResponse.new(last_requested_endpoint, setup_url) end end def complete_id_res(message, current_url) if message.is_openid1 setup_url = message.get_arg(OPENID_NS, 'user_setup_url') if !setup_url.nil? return SetupNeededResponse.new(last_requested_endpoint, setup_url) end end begin idres = handle_idres(message, current_url) rescue OpenIDError => why return FailureResponse.new(last_requested_endpoint, why.message) else return SuccessResponse.new(idres.endpoint, message, idres.signed_fields) end end end end ruby-openid-2.7.0debian.orig/lib/openid/fetchers.rb0000644000175000017500000001664512512544714021504 0ustar sbadiasbadiarequire 'net/http' require 'openid' require 'openid/util' begin require 'net/https' rescue LoadError OpenID::Util.log('WARNING: no SSL support found. Will not be able ' + 'to fetch HTTPS URLs!') require 'net/http' end MAX_RESPONSE_KB = 10485760 # 10 MB (can be smaller, I guess) module Net class HTTP def post_connection_check(hostname) check_common_name = true cert = @socket.io.peer_cert cert.extensions.each { |ext| next if ext.oid != "subjectAltName" ext.value.split(/,\s+/).each{ |general_name| if /\ADNS:(.*)/ =~ general_name check_common_name = false reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname elsif /\AIP Address:(.*)/ =~ general_name check_common_name = false return true if $1 == hostname end } } if check_common_name cert.subject.to_a.each{ |oid, value| if oid == "CN" reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname end } end raise OpenSSL::SSL::SSLError, "hostname does not match" end end end module OpenID # Our HTTPResponse class extends Net::HTTPResponse with an additional # method, final_url. class HTTPResponse attr_accessor :final_url attr_accessor :_response def self._from_net_response(response, final_url, headers=nil) me = self.new me._response = response me.final_url = final_url return me end def method_missing(method, *args) @_response.send(method, *args) end def body=(s) @_response.instance_variable_set('@body', s) # XXX Hack to work around ruby's HTTP library behavior. @body # is only returned if it has been read from the response # object's socket, but since we're not using a socket in this # case, we need to set the @read flag to true to avoid a bug in # Net::HTTPResponse.stream_check when @socket is nil. @_response.instance_variable_set('@read', true) end end class FetchingError < OpenIDError end class HTTPRedirectLimitReached < FetchingError end class SSLFetchingError < FetchingError end @fetcher = nil def self.fetch(url, body=nil, headers=nil, redirect_limit=StandardFetcher::REDIRECT_LIMIT) return fetcher.fetch(url, body, headers, redirect_limit) end def self.fetcher if @fetcher.nil? @fetcher = StandardFetcher.new end return @fetcher end def self.fetcher=(fetcher) @fetcher = fetcher end # Set the default fetcher to use the HTTP proxy defined in the environment # variable 'http_proxy'. def self.fetcher_use_env_http_proxy proxy_string = ENV['http_proxy'] return unless proxy_string proxy_uri = URI.parse(proxy_string) @fetcher = StandardFetcher.new(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password) end class StandardFetcher USER_AGENT = "ruby-openid/#{OpenID::VERSION} (#{RUBY_PLATFORM})" REDIRECT_LIMIT = 5 TIMEOUT = 60 attr_accessor :ca_file attr_accessor :timeout # I can fetch through a HTTP proxy; arguments are as for Net::HTTP::Proxy. def initialize(proxy_addr=nil, proxy_port=nil, proxy_user=nil, proxy_pass=nil) @ca_file = nil @proxy = Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user, proxy_pass) @timeout = TIMEOUT end def supports_ssl?(conn) return conn.respond_to?(:use_ssl=) end def make_http(uri) http = @proxy.new(uri.host, uri.port) http.read_timeout = @timeout http.open_timeout = @timeout return http end def set_verified(conn, verify) if verify conn.verify_mode = OpenSSL::SSL::VERIFY_PEER else conn.verify_mode = OpenSSL::SSL::VERIFY_NONE end end def make_connection(uri) conn = make_http(uri) if !conn.is_a?(Net::HTTP) raise RuntimeError, sprintf("Expected Net::HTTP object from make_http; got %s", conn.class) end if uri.scheme == 'https' if supports_ssl?(conn) conn.use_ssl = true if @ca_file set_verified(conn, true) conn.ca_file = @ca_file else Util.log("WARNING: making https request to #{uri} without verifying " + "server certificate; no CA path was specified.") set_verified(conn, false) end else raise RuntimeError, "SSL support not found; cannot fetch #{uri}" end end return conn end def fetch(url, body=nil, headers=nil, redirect_limit=REDIRECT_LIMIT) unparsed_url = url.dup url = URI::parse(url) if url.nil? raise FetchingError, "Invalid URL: #{unparsed_url}" end headers ||= {} headers['User-agent'] ||= USER_AGENT begin conn = make_connection(url) response = nil whole_body = '' body_size_limitter = lambda do |r| r.read_body do |partial| # read body now whole_body << partial if whole_body.length > MAX_RESPONSE_KB raise FetchingError.new("Response Too Large") end end whole_body end response = conn.start { # Check the certificate against the URL's hostname if supports_ssl?(conn) and conn.use_ssl? conn.post_connection_check(url.host) end if body.nil? conn.request_get(url.request_uri, headers, &body_size_limitter) else headers["Content-type"] ||= "application/x-www-form-urlencoded" conn.request_post(url.request_uri, body, headers, &body_size_limitter) end } rescue Timeout::Error => why raise FetchingError, "Error fetching #{url}: #{why}" rescue RuntimeError => why raise why rescue OpenSSL::SSL::SSLError => why raise SSLFetchingError, "Error connecting to SSL URL #{url}: #{why}" rescue FetchingError => why raise why rescue Exception => why raise FetchingError, "Error fetching #{url}: #{why}" end case response when Net::HTTPRedirection if redirect_limit <= 0 raise HTTPRedirectLimitReached.new( "Too many redirects, not fetching #{response['location']}") end begin return fetch(response['location'], body, headers, redirect_limit - 1) rescue HTTPRedirectLimitReached => e raise e rescue FetchingError => why raise FetchingError, "Error encountered in redirect from #{url}: #{why}" end else response = HTTPResponse._from_net_response(response, unparsed_url) response.body = whole_body setup_encoding(response) return response end end private def setup_encoding(response) return unless defined?(Encoding.default_external) return unless charset = response.type_params["charset"] begin encoding = Encoding.find(charset) rescue ArgumentError end encoding ||= Encoding.default_external body = response.body if body.respond_to?(:force_encoding) body.force_encoding(encoding) else body.set_encoding(encoding) end end end end ruby-openid-2.7.0debian.orig/lib/openid/extensions/0000755000175000017500000000000012512544714021537 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/lib/openid/extensions/oauth.rb0000644000175000017500000000475612512544714023220 0ustar sbadiasbadia# An implementation of the OpenID OAuth Extension # Extension 1.0 # see: http://openid.net/specs/ require 'openid/extension' module OpenID module OAuth NS_URI = "http://specs.openid.net/extensions/oauth/1.0" # An OAuth token request, sent from a relying # party to a provider class Request < Extension attr_accessor :consumer, :scope, :ns_alias, :ns_uri def initialize(consumer=nil, scope=nil) @ns_alias = 'oauth' @ns_uri = NS_URI @consumer = consumer @scope = scope end def get_extension_args ns_args = {} ns_args['consumer'] = @consumer if @consumer ns_args['scope'] = @scope if @scope return ns_args end # Instantiate a Request object from the arguments in a # checkid_* OpenID message # return nil if the extension was not requested. def self.from_openid_request(oid_req) oauth_req = new args = oid_req.message.get_args(NS_URI) if args == {} return nil end oauth_req.parse_extension_args(args) return oauth_req end # Set the state of this request to be that expressed in these # OAuth arguments def parse_extension_args(args) @consumer = args["consumer"] @scope = args["scope"] end end # A OAuth request token response, sent from a provider # to a relying party class Response < Extension attr_accessor :request_token, :scope def initialize(request_token=nil, scope=nil) @ns_alias = 'oauth' @ns_uri = NS_URI @request_token = request_token @scope = scope end # Create a Response object from an OpenID::Consumer::SuccessResponse def self.from_success_response(success_response) args = success_response.get_signed_ns(NS_URI) return nil if args.nil? oauth_resp = new oauth_resp.parse_extension_args(args) return oauth_resp end # parse the oauth request arguments into the # internal state of this object # if strict is specified, raise an exception when bad data is # encountered def parse_extension_args(args, strict=false) @request_token = args["request_token"] @scope = args["scope"] end def get_extension_args ns_args = {} ns_args['request_token'] = @request_token if @request_token ns_args['scope'] = @scope if @scope return ns_args end end end end ruby-openid-2.7.0debian.orig/lib/openid/extensions/ax.rb0000644000175000017500000004254212512544714022503 0ustar sbadiasbadia# Implements the OpenID attribute exchange specification, version 1.0 require 'openid/extension' require 'openid/trustroot' require 'openid/message' module OpenID module AX UNLIMITED_VALUES = "unlimited" MINIMUM_SUPPORTED_ALIAS_LENGTH = 32 # check alias for invalid characters, raise AXError if found def self.check_alias(name) if name.match(/(,|\.)/) raise Error, ("Alias #{name.inspect} must not contain a "\ "comma or period.") end end # Raised when data does not comply with AX 1.0 specification class Error < ArgumentError end # Abstract class containing common code for attribute exchange messages class AXMessage < Extension attr_accessor :ns_alias, :mode, :ns_uri NS_URI = 'http://openid.net/srv/ax/1.0' begin Message.register_namespace_alias(NS_URI, 'ax') rescue NamespaceAliasRegistrationError => e Util.log(e) end def initialize @ns_alias = 'ax' @ns_uri = NS_URI @mode = nil end protected # Raise an exception if the mode in the attribute exchange # arguments does not match what is expected for this class. def check_mode(ax_args) actual_mode = ax_args ? ax_args['mode'] : nil if actual_mode != @mode raise Error, "Expected mode #{mode.inspect}, got #{actual_mode.inspect}" end end def new_args {'mode' => @mode} end end # Represents a single attribute in an attribute exchange # request. This should be added to an Request object in order to # request the attribute. # # @ivar required: Whether the attribute will be marked as required # when presented to the subject of the attribute exchange # request. # @type required: bool # # @ivar count: How many values of this type to request from the # subject. Defaults to one. # @type count: int # # @ivar type_uri: The identifier that determines what the attribute # represents and how it is serialized. For example, one type URI # representing dates could represent a Unix timestamp in base 10 # and another could represent a human-readable string. # @type type_uri: str # # @ivar ns_alias: The name that should be given to this alias in the # request. If it is not supplied, a generic name will be # assigned. For example, if you want to call a Unix timestamp # value 'tstamp', set its alias to that value. If two attributes # in the same message request to use the same alias, the request # will fail to be generated. # @type alias: str or NoneType class AttrInfo < Object attr_reader :type_uri, :count, :ns_alias attr_accessor :required def initialize(type_uri, ns_alias=nil, required=false, count=1) @type_uri = type_uri @count = count @required = required @ns_alias = ns_alias end def wants_unlimited_values? @count == UNLIMITED_VALUES end end # Given a namespace mapping and a string containing a # comma-separated list of namespace aliases, return a list of type # URIs that correspond to those aliases. # namespace_map: OpenID::NamespaceMap def self.to_type_uris(namespace_map, alias_list_s) return [] if alias_list_s.nil? alias_list_s.split(',').inject([]) {|uris, name| type_uri = namespace_map.get_namespace_uri(name) raise IndexError, "No type defined for attribute name #{name.inspect}" if type_uri.nil? uris << type_uri } end # An attribute exchange 'fetch_request' message. This message is # sent by a relying party when it wishes to obtain attributes about # the subject of an OpenID authentication request. class FetchRequest < AXMessage attr_reader :requested_attributes attr_accessor :update_url MODE = 'fetch_request' def initialize(update_url = nil) super() @mode = MODE @requested_attributes = {} @update_url = update_url end # Add an attribute to this attribute exchange request. # attribute: AttrInfo, the attribute being requested # Raises IndexError if the requested attribute is already present # in this request. def add(attribute) if @requested_attributes[attribute.type_uri] raise IndexError, "The attribute #{attribute.type_uri} has already been requested" end @requested_attributes[attribute.type_uri] = attribute end # Get the serialized form of this attribute fetch request. # returns a hash of the arguments def get_extension_args aliases = NamespaceMap.new required = [] if_available = [] ax_args = new_args @requested_attributes.each{|type_uri, attribute| if attribute.ns_alias name = aliases.add_alias(type_uri, attribute.ns_alias) else name = aliases.add(type_uri) end if attribute.required required << name else if_available << name end if attribute.count != 1 ax_args["count.#{name}"] = attribute.count.to_s end ax_args["type.#{name}"] = type_uri } unless required.empty? ax_args['required'] = required.join(',') end unless if_available.empty? ax_args['if_available'] = if_available.join(',') end return ax_args end # Get the type URIs for all attributes that have been marked # as required. def get_required_attrs @requested_attributes.inject([]) {|required, (type_uri, attribute)| if attribute.required required << type_uri else required end } end # Extract a FetchRequest from an OpenID message # message: OpenID::Message # return a FetchRequest or nil if AX arguments are not present def self.from_openid_request(oidreq) message = oidreq.message ax_args = message.get_args(NS_URI) return nil if ax_args == {} or ax_args['mode'] != MODE req = new req.parse_extension_args(ax_args) if req.update_url realm = message.get_arg(OPENID_NS, 'realm', message.get_arg(OPENID_NS, 'return_to')) if realm.nil? or realm.empty? raise Error, "Cannot validate update_url #{req.update_url.inspect} against absent realm" end tr = TrustRoot::TrustRoot.parse(realm) unless tr.validate_url(req.update_url) raise Error, "Update URL #{req.update_url.inspect} failed validation against realm #{realm.inspect}" end end return req end def parse_extension_args(ax_args) check_mode(ax_args) aliases = NamespaceMap.new ax_args.each{|k,v| if k.index('type.') == 0 name = k[5..-1] type_uri = v aliases.add_alias(type_uri, name) count_key = 'count.'+name count_s = ax_args[count_key] count = 1 if count_s if count_s == UNLIMITED_VALUES count = count_s else count = count_s.to_i if count <= 0 raise Error, "Invalid value for count #{count_key.inspect}: #{count_s.inspect}" end end end add(AttrInfo.new(type_uri, name, false, count)) end } required = AX.to_type_uris(aliases, ax_args['required']) required.each{|type_uri| @requested_attributes[type_uri].required = true } if_available = AX.to_type_uris(aliases, ax_args['if_available']) all_type_uris = required + if_available aliases.namespace_uris.each{|type_uri| unless all_type_uris.member? type_uri raise Error, "Type URI #{type_uri.inspect} was in the request but not present in 'required' or 'if_available'" end } @update_url = ax_args['update_url'] end # return the list of AttrInfo objects contained in the FetchRequest def attributes @requested_attributes.values end # return the list of requested attribute type URIs def requested_types @requested_attributes.keys end def member?(type_uri) ! @requested_attributes[type_uri].nil? end end # Abstract class that implements a message that has attribute # keys and values. It contains the common code between # fetch_response and store_request. class KeyValueMessage < AXMessage attr_reader :data def initialize super() @mode = nil @data = Hash.new { |hash, key| hash[key] = [] } end # Add a single value for the given attribute type to the # message. If there are already values specified for this type, # this value will be sent in addition to the values already # specified. def add_value(type_uri, value) @data[type_uri] = @data[type_uri] << value end # Set the values for the given attribute type. This replaces # any values that have already been set for this attribute. def set_values(type_uri, values) @data[type_uri] = values end # Get the extension arguments for the key/value pairs # contained in this message. def _get_extension_kv_args(aliases = nil) aliases = NamespaceMap.new if aliases.nil? ax_args = new_args @data.each{|type_uri, values| name = aliases.add(type_uri) ax_args['type.'+name] = type_uri if values.size > 1 ax_args['count.'+name] = values.size.to_s values.each_with_index{|value, i| key = "value.#{name}.#{i+1}" ax_args[key] = value } # for attributes with only a single value, use a # nice shortcut to only show the value w/o the count else values.each do |value| key = "value.#{name}" ax_args[key] = value end end } return ax_args end # Parse attribute exchange key/value arguments into this object. def parse_extension_args(ax_args) check_mode(ax_args) aliases = NamespaceMap.new ax_args.each{|k, v| if k.index('type.') == 0 type_uri = v name = k[5..-1] AX.check_alias(name) aliases.add_alias(type_uri,name) end } aliases.each{|type_uri, name| count_s = ax_args['count.'+name] count = count_s.to_i if count_s.nil? value = ax_args['value.'+name] if value.nil? raise IndexError, "Missing #{'value.'+name} in FetchResponse" elsif value.empty? values = [] else values = [value] end elsif count_s.to_i == 0 values = [] else values = (1..count).inject([]){|l,i| key = "value.#{name}.#{i}" v = ax_args[key] raise IndexError, "Missing #{key} in FetchResponse" if v.nil? l << v } end @data[type_uri] = values } end # Get a single value for an attribute. If no value was sent # for this attribute, use the supplied default. If there is more # than one value for this attribute, this method will fail. def get_single(type_uri, default = nil) values = @data[type_uri] return default if values.empty? if values.size != 1 raise Error, "More than one value present for #{type_uri.inspect}" else return values[0] end end # retrieve the list of values for this attribute def get(type_uri) @data[type_uri] end # retrieve the list of values for this attribute def [](type_uri) @data[type_uri] end # get the number of responses for this attribute def count(type_uri) @data[type_uri].size end end # A fetch_response attribute exchange message class FetchResponse < KeyValueMessage attr_reader :update_url # Use the aliases variable to manually add alias names in the response. # They'll be returned to the client in the format: # openid.ax.type.email=http://openid.net/schema/contact/internet/email # openid.ax.value.email=guy@example.com attr_accessor :aliases def initialize(update_url = nil) super() @mode = 'fetch_response' @update_url = update_url @aliases = NamespaceMap.new end # Serialize this object into arguments in the attribute # exchange namespace # Takes an optional FetchRequest. If specified, the response will be # validated against this request, and empty responses for requested # fields with no data will be sent. def get_extension_args(request = nil) zero_value_types = [] if request # Validate the data in the context of the request (the # same attributes should be present in each, and the # counts in the response must be no more than the counts # in the request) @data.keys.each{|type_uri| unless request.member? type_uri raise IndexError, "Response attribute not present in request: #{type_uri.inspect}" end } request.attributes.each{|attr_info| # Copy the aliases from the request so that reading # the response in light of the request is easier if attr_info.ns_alias.nil? @aliases.add(attr_info.type_uri) else @aliases.add_alias(attr_info.type_uri, attr_info.ns_alias) end values = @data[attr_info.type_uri] if values.empty? # @data defaults to [] zero_value_types << attr_info end if attr_info.count != UNLIMITED_VALUES and attr_info.count < values.size raise Error, "More than the number of requested values were specified for #{attr_info.type_uri.inspect}" end } end kv_args = _get_extension_kv_args(@aliases) # Add the KV args into the response with the args that are # unique to the fetch_response ax_args = new_args zero_value_types.each{|attr_info| name = @aliases.get_alias(attr_info.type_uri) kv_args['type.' + name] = attr_info.type_uri kv_args['count.' + name] = '0' } update_url = (request and request.update_url or @update_url) ax_args['update_url'] = update_url unless update_url.nil? ax_args.update(kv_args) return ax_args end def parse_extension_args(ax_args) super @update_url = ax_args['update_url'] end # Construct a FetchResponse object from an OpenID library # SuccessResponse object. def self.from_success_response(success_response, signed=true) obj = self.new if signed ax_args = success_response.get_signed_ns(obj.ns_uri) else ax_args = success_response.message.get_args(obj.ns_uri) end begin obj.parse_extension_args(ax_args) return obj rescue Error return nil end end end # A store request attribute exchange message representation class StoreRequest < KeyValueMessage MODE = 'store_request' def initialize super @mode = MODE end # Extract a StoreRequest from an OpenID message # message: OpenID::Message # return a StoreRequest or nil if AX arguments are not present def self.from_openid_request(oidreq) message = oidreq.message ax_args = message.get_args(NS_URI) return nil if ax_args.empty? or ax_args['mode'] != MODE req = new req.parse_extension_args(ax_args) req end def get_extension_args(aliases=nil) ax_args = new_args kv_args = _get_extension_kv_args(aliases) ax_args.update(kv_args) return ax_args end end # An indication that the store request was processed along with # this OpenID transaction. class StoreResponse < AXMessage SUCCESS_MODE = 'store_response_success' FAILURE_MODE = 'store_response_failure' attr_reader :error_message def initialize(succeeded = true, error_message = nil) super() if succeeded and error_message raise Error, "Error message included in a success response" end if succeeded @mode = SUCCESS_MODE else @mode = FAILURE_MODE end @error_message = error_message end def self.from_success_response(success_response) resp = nil ax_args = success_response.message.get_args(NS_URI) resp = ax_args.key?('error') ? new(false, ax_args['error']) : new end def succeeded? @mode == SUCCESS_MODE end def get_extension_args ax_args = new_args if !succeeded? and error_message ax_args['error'] = @error_message end return ax_args end end end end ruby-openid-2.7.0debian.orig/lib/openid/extensions/sreg.rb0000644000175000017500000002257612512544714023040 0ustar sbadiasbadiarequire 'openid/extension' require 'openid/util' require 'openid/message' module OpenID module SReg DATA_FIELDS = { 'fullname'=>'Full Name', 'nickname'=>'Nickname', 'dob'=>'Date of Birth', 'email'=>'E-mail Address', 'gender'=>'Gender', 'postcode'=>'Postal Code', 'country'=>'Country', 'language'=>'Language', 'timezone'=>'Time Zone', } NS_URI_1_0 = 'http://openid.net/sreg/1.0' NS_URI_1_1 = 'http://openid.net/extensions/sreg/1.1' NS_URI = NS_URI_1_1 begin Message.register_namespace_alias(NS_URI_1_1, 'sreg') rescue NamespaceAliasRegistrationError => e Util.log(e) end # raise ArgumentError if fieldname is not in the defined sreg fields def OpenID.check_sreg_field_name(fieldname) unless DATA_FIELDS.member? fieldname raise ArgumentError, "#{fieldname} is not a defined simple registration field" end end # Does the given endpoint advertise support for simple registration? def OpenID.supports_sreg?(endpoint) endpoint.uses_extension(NS_URI_1_1) || endpoint.uses_extension(NS_URI_1_0) end # Extract the simple registration namespace URI from the given # OpenID message. Handles OpenID 1 and 2, as well as both sreg # namespace URIs found in the wild, as well as missing namespace # definitions (for OpenID 1) def OpenID.get_sreg_ns(message) [NS_URI_1_1, NS_URI_1_0].each{|ns| if message.namespaces.get_alias(ns) return ns end } # try to add an alias, since we didn't find one ns = NS_URI_1_1 begin message.namespaces.add_alias(ns, 'sreg') rescue IndexError raise NamespaceError end return ns end # The simple registration namespace was not found and could not # be created using the expected name (there's another extension # using the name 'sreg') # # This is not illegal, for OpenID 2, although it probably # indicates a problem, since it's not expected that other extensions # will re-use the alias that is in use for OpenID 1. # # If this is an OpenID 1 request, then there is no recourse. This # should not happen unless some code has modified the namespaces for # the message that is being processed. class NamespaceError < ArgumentError end # An object to hold the state of a simple registration request. class Request < Extension attr_reader :optional, :required, :ns_uri attr_accessor :policy_url def initialize(required = nil, optional = nil, policy_url = nil, ns_uri = NS_URI) super() @policy_url = policy_url @ns_uri = ns_uri @ns_alias = 'sreg' @required = [] @optional = [] if required request_fields(required, true, true) end if optional request_fields(optional, false, true) end end # Create a simple registration request that contains the # fields that were requested in the OpenID request with the # given arguments # Takes an OpenID::CheckIDRequest, returns an OpenID::Sreg::Request # return nil if the extension was not requested. def self.from_openid_request(request) # Since we're going to mess with namespace URI mapping, don't # mutate the object that was passed in. message = request.message.copy ns_uri = OpenID::get_sreg_ns(message) args = message.get_args(ns_uri) return nil if args == {} req = new(nil,nil,nil,ns_uri) req.parse_extension_args(args) return req end # Parse the unqualified simple registration request # parameters and add them to this object. # # This method is essentially the inverse of # getExtensionArgs. This method restores the serialized simple # registration request fields. # # If you are extracting arguments from a standard OpenID # checkid_* request, you probably want to use fromOpenIDRequest, # which will extract the sreg namespace and arguments from the # OpenID request. This method is intended for cases where the # OpenID server needs more control over how the arguments are # parsed than that method provides. def parse_extension_args(args, strict = false) required_items = args['required'] unless required_items.nil? or required_items.empty? required_items.split(',').each{|field_name| begin request_field(field_name, true, strict) rescue ArgumentError raise if strict end } end optional_items = args['optional'] unless optional_items.nil? or optional_items.empty? optional_items.split(',').each{|field_name| begin request_field(field_name, false, strict) rescue ArgumentError raise if strict end } end @policy_url = args['policy_url'] end # A list of all of the simple registration fields that were # requested, whether they were required or optional. def all_requested_fields @required + @optional end # Have any simple registration fields been requested? def were_fields_requested? !all_requested_fields.empty? end # Request the specified field from the OpenID user # field_name: the unqualified simple registration field name # required: whether the given field should be presented # to the user as being a required to successfully complete # the request # strict: whether to raise an exception when a field is # added to a request more than once # Raises ArgumentError if the field_name is not a simple registration # field, or if strict is set and a field is added more than once def request_field(field_name, required=false, strict=false) OpenID::check_sreg_field_name(field_name) if strict if (@required + @optional).member? field_name raise ArgumentError, 'That field has already been requested' end else return if @required.member? field_name if @optional.member? field_name if required @optional.delete field_name else return end end end if required @required << field_name else @optional << field_name end end # Add the given list of fields to the request. def request_fields(field_names, required = false, strict = false) raise ArgumentError unless field_names.respond_to?(:each) and field_names[0].is_a?(String) field_names.each{|fn|request_field(fn, required, strict)} end # Get a hash of unqualified simple registration arguments # representing this request. # This method is essentially the inverse of parse_extension_args. # This method serializes the simple registration request fields. def get_extension_args args = {} args['required'] = @required.join(',') unless @required.empty? args['optional'] = @optional.join(',') unless @optional.empty? args['policy_url'] = @policy_url unless @policy_url.nil? return args end def member?(field_name) all_requested_fields.member?(field_name) end end # Represents the data returned in a simple registration response # inside of an OpenID id_res response. This object will be # created by the OpenID server, added to the id_res response # object, and then extracted from the id_res message by the Consumer. class Response < Extension attr_reader :ns_uri, :data def initialize(data = {}, ns_uri=NS_URI) @ns_alias = 'sreg' @data = data @ns_uri = ns_uri end # Take a Request and a hash of simple registration # values and create a Response object containing that data. def self.extract_response(request, data) arf = request.all_requested_fields resp_data = data.reject{|k,v| !arf.member?(k) || v.nil? } new(resp_data, request.ns_uri) end # Create an Response object from an # OpenID::Consumer::SuccessResponse from consumer.complete # If you set the signed_only parameter to false, unsigned data from # the id_res message from the server will be processed. def self.from_success_response(success_response, signed_only = true) ns_uri = OpenID::get_sreg_ns(success_response.message) if signed_only args = success_response.get_signed_ns(ns_uri) return nil if args.nil? # No signed args, so fail else args = success_response.message.get_args(ns_uri) end args.reject!{|k,v| !DATA_FIELDS.member?(k) } new(args, ns_uri) end # Get the fields to put in the simple registration namespace # when adding them to an id_res message. def get_extension_args return @data end # Read-only hashlike interface. # Raises an exception if the field name is bad def [](field_name) OpenID::check_sreg_field_name(field_name) data[field_name] end def empty? @data.empty? end # XXX is there more to a hashlike interface I should add? end end end ruby-openid-2.7.0debian.orig/lib/openid/extensions/ui.rb0000644000175000017500000000252612512544714022506 0ustar sbadiasbadia# An implementation of the OpenID User Interface Extension 1.0 - DRAFT 0.5 # see: http://svn.openid.net/repos/specifications/user_interface/1.0/trunk/openid-user-interface-extension-1_0.html require 'openid/extension' module OpenID module UI NS_URI = "http://specs.openid.net/extensions/ui/1.0" class Request < Extension attr_accessor :lang, :icon, :mode, :ns_alias, :ns_uri def initialize(mode = nil, icon = nil, lang = nil) @ns_alias = 'ui' @ns_uri = NS_URI @lang = lang @icon = icon @mode = mode end def get_extension_args ns_args = {} ns_args['lang'] = @lang if @lang ns_args['icon'] = @icon if @icon ns_args['mode'] = @mode if @mode return ns_args end # Instantiate a Request object from the arguments in a # checkid_* OpenID message # return nil if the extension was not requested. def self.from_openid_request(oid_req) ui_req = new args = oid_req.message.get_args(NS_URI) if args == {} return nil end ui_req.parse_extension_args(args) return ui_req end # Set UI extension parameters def parse_extension_args(args) @lang = args["lang"] @icon = args["icon"] @mode = args["mode"] end end end end ruby-openid-2.7.0debian.orig/lib/openid/extensions/pape.rb0000644000175000017500000001370312512544714023015 0ustar sbadiasbadia# An implementation of the OpenID Provider Authentication Policy # Extension 1.0 # see: http://openid.net/specs/ require 'openid/extension' module OpenID module PAPE NS_URI = "http://specs.openid.net/extensions/pape/1.0" AUTH_MULTI_FACTOR_PHYSICAL = 'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical' AUTH_MULTI_FACTOR = 'http://schemas.openid.net/pape/policies/2007/06/multi-factor' AUTH_PHISHING_RESISTANT = 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant' TIME_VALIDATOR = /\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/ # A Provider Authentication Policy request, sent from a relying # party to a provider class Request < Extension attr_accessor :preferred_auth_policies, :max_auth_age, :ns_alias, :ns_uri def initialize(preferred_auth_policies=[], max_auth_age=nil) @ns_alias = 'pape' @ns_uri = NS_URI @preferred_auth_policies = preferred_auth_policies @max_auth_age = max_auth_age end # Add an acceptable authentication policy URI to this request # This method is intended to be used by the relying party to add # acceptable authentication types to the request. def add_policy_uri(policy_uri) unless @preferred_auth_policies.member? policy_uri @preferred_auth_policies << policy_uri end end def get_extension_args ns_args = { 'preferred_auth_policies' => @preferred_auth_policies.join(' ') } ns_args['max_auth_age'] = @max_auth_age.to_s if @max_auth_age return ns_args end # Instantiate a Request object from the arguments in a # checkid_* OpenID message # return nil if the extension was not requested. def self.from_openid_request(oid_req) pape_req = new args = oid_req.message.get_args(NS_URI) if args == {} return nil end pape_req.parse_extension_args(args) return pape_req end # Set the state of this request to be that expressed in these # PAPE arguments def parse_extension_args(args) @preferred_auth_policies = [] policies_str = args['preferred_auth_policies'] if policies_str policies_str.split(' ').each{|uri| add_policy_uri(uri) } end max_auth_age_str = args['max_auth_age'] if max_auth_age_str @max_auth_age = max_auth_age_str.to_i else @max_auth_age = nil end end # Given a list of authentication policy URIs that a provider # supports, this method returns the subset of those types # that are preferred by the relying party. def preferred_types(supported_types) @preferred_auth_policies.select{|uri| supported_types.member? uri} end end # A Provider Authentication Policy response, sent from a provider # to a relying party class Response < Extension attr_accessor :ns_alias, :auth_policies, :auth_time, :nist_auth_level def initialize(auth_policies=[], auth_time=nil, nist_auth_level=nil) @ns_alias = 'pape' @ns_uri = NS_URI @auth_policies = auth_policies @auth_time = auth_time @nist_auth_level = nist_auth_level end # Add a policy URI to the response # see http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies def add_policy_uri(policy_uri) @auth_policies << policy_uri unless @auth_policies.member?(policy_uri) end # Create a Response object from an OpenID::Consumer::SuccessResponse def self.from_success_response(success_response) args = success_response.get_signed_ns(NS_URI) return nil if args.nil? pape_resp = new pape_resp.parse_extension_args(args) return pape_resp end # parse the provider authentication policy arguments into the # internal state of this object # if strict is specified, raise an exception when bad data is # encountered def parse_extension_args(args, strict=false) policies_str = args['auth_policies'] if policies_str and policies_str != 'none' @auth_policies = policies_str.split(' ') end nist_level_str = args['nist_auth_level'] if nist_level_str # special handling of zero to handle to_i behavior if nist_level_str.strip == '0' nist_level = 0 else nist_level = nist_level_str.to_i # if it's zero here we have a bad value if nist_level == 0 nist_level = nil end end if nist_level and nist_level >= 0 and nist_level < 5 @nist_auth_level = nist_level elsif strict raise ArgumentError, "nist_auth_level must be an integer 0 through 4, not #{nist_level_str.inspect}" end end auth_time_str = args['auth_time'] if auth_time_str # validate time string if auth_time_str =~ TIME_VALIDATOR @auth_time = auth_time_str elsif strict raise ArgumentError, "auth_time must be in RFC3339 format" end end end def get_extension_args ns_args = {} if @auth_policies.empty? ns_args['auth_policies'] = 'none' else ns_args['auth_policies'] = @auth_policies.join(' ') end if @nist_auth_level unless (0..4).member? @nist_auth_level raise ArgumentError, "nist_auth_level must be an integer 0 through 4, not #{@nist_auth_level.inspect}" end ns_args['nist_auth_level'] = @nist_auth_level.to_s end if @auth_time unless @auth_time =~ TIME_VALIDATOR raise ArgumentError, "auth_time must be in RFC3339 format" end ns_args['auth_time'] = @auth_time end return ns_args end end end end ruby-openid-2.7.0debian.orig/lib/openid/protocolerror.rb0000644000175000017500000000017012512544714022576 0ustar sbadiasbadiarequire 'openid/util' module OpenID # An error in the OpenID protocol class ProtocolError < OpenIDError end end ruby-openid-2.7.0debian.orig/lib/openid/kvpost.rb0000644000175000017500000000317112512544714021215 0ustar sbadiasbadiarequire "openid/message" require "openid/fetchers" module OpenID # Exception that is raised when the server returns a 400 response # code to a direct request. class ServerError < OpenIDError attr_reader :error_text, :error_code, :message def initialize(error_text, error_code, message) super(error_text) @error_text = error_text @error_code = error_code @message = message end def self.from_message(msg) error_text = msg.get_arg(OPENID_NS, 'error', '') error_code = msg.get_arg(OPENID_NS, 'error_code') return self.new(error_text, error_code, msg) end end class KVPostNetworkError < OpenIDError end class HTTPStatusError < OpenIDError end class Message def self.from_http_response(response, server_url) msg = self.from_kvform(response.body) case response.code.to_i when 200 return msg when 206 return msg when 400 raise ServerError.from_message(msg) else error_message = "bad status code from server #{server_url}: "\ "#{response.code}" raise HTTPStatusError.new(error_message) end end end # Send the message to the server via HTTP POST and receive and parse # a response in KV Form def self.make_kv_post(request_message, server_url) begin http_response = self.fetch(server_url, request_message.to_url_encoded) rescue Exception raise KVPostNetworkError.new("Unable to contact OpenID server: #{$!.to_s}") end return Message.from_http_response(http_response, server_url) end end ruby-openid-2.7.0debian.orig/lib/openid/extension.rb0000644000175000017500000000217612512544714021707 0ustar sbadiasbadiarequire 'openid/message' module OpenID # An interface for OpenID extensions. class Extension < Object def initialize @ns_uri = nil @ns_alias = nil end # Get the string arguments that should be added to an OpenID # message for this extension. def get_extension_args raise NotImplementedError end # Add the arguments from this extension to the provided # message, or create a new message containing only those # arguments. Returns the message with added extension args. def to_message(message = nil) if message.nil? # warnings.warn('Passing None to Extension.toMessage is deprecated. ' # 'Creating a message assuming you want OpenID 2.', # DeprecationWarning, stacklevel=2) Message.new(OPENID2_NS) end message = Message.new if message.nil? implicit = message.is_openid1() message.namespaces.add_alias(@ns_uri, @ns_alias, implicit) # XXX python ignores keyerror if m.ns.getAlias(uri) == alias message.update_args(@ns_uri, get_extension_args) return message end end end ruby-openid-2.7.0debian.orig/lib/openid/store/0000755000175000017500000000000012512544714020474 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/lib/openid/store/nonce.rb0000644000175000017500000000366612512544714022136 0ustar sbadiasbadiarequire 'openid/cryptutil' require 'date' require 'time' module OpenID module Nonce DEFAULT_SKEW = 60*60*5 TIME_FMT = '%Y-%m-%dT%H:%M:%SZ' TIME_STR_LEN = '0000-00-00T00:00:00Z'.size @@NONCE_CHRS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" TIME_VALIDATOR = /\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/ @skew = DEFAULT_SKEW # The allowed nonce time skew in seconds. Defaults to 5 hours. # Used for checking nonce validity, and by stores' cleanup methods. def Nonce.skew @skew end def Nonce.skew=(new_skew) @skew = new_skew end # Extract timestamp from a nonce string def Nonce.split_nonce(nonce_str) timestamp_str = nonce_str[0...TIME_STR_LEN] raise ArgumentError if timestamp_str.size < TIME_STR_LEN raise ArgumentError unless timestamp_str.match(TIME_VALIDATOR) ts = Time.parse(timestamp_str).to_i raise ArgumentError if ts < 0 return ts, nonce_str[TIME_STR_LEN..-1] end # Is the timestamp that is part of the specified nonce string # within the allowed clock-skew of the current time? def Nonce.check_timestamp(nonce_str, allowed_skew=nil, now=nil) allowed_skew = skew if allowed_skew.nil? begin stamp, _ = split_nonce(nonce_str) rescue ArgumentError # bad timestamp return false end now = Time.now.to_i unless now # times before this are too old past = now - allowed_skew # times newer than this are too far in the future future = now + allowed_skew return (past <= stamp and stamp <= future) end # generate a nonce with the specified timestamp (defaults to now) def Nonce.mk_nonce(time = nil) salt = CryptUtil::random_string(6, @@NONCE_CHRS) if time.nil? t = Time.now.getutc else t = Time.at(time).getutc end time_str = t.strftime(TIME_FMT) return time_str + salt end end end ruby-openid-2.7.0debian.orig/lib/openid/store/memory.rb0000644000175000017500000000411312512544714022330 0ustar sbadiasbadiarequire 'openid/store/interface' module OpenID module Store # An in-memory implementation of Store. This class is mainly used # for testing, though it may be useful for long-running single # process apps. Note that this store is NOT thread-safe. # # You should probably be looking at OpenID::Store::Filesystem class Memory < Interface def initialize @associations = Hash.new { |hash, key| hash[key] = {} } @nonces = {} end def store_association(server_url, assoc) assocs = @associations[server_url] @associations[server_url] = assocs.merge({assoc.handle => deepcopy(assoc)}) end def get_association(server_url, handle=nil) assocs = @associations[server_url] assoc = nil if handle assoc = assocs[handle] else assoc = assocs.values.sort{|a,b| a.issued <=> b.issued}[-1] end return assoc end def remove_association(server_url, handle) assocs = @associations[server_url] if assocs.delete(handle) return true else return false end end def use_nonce(server_url, timestamp, salt) return false if (timestamp - Time.now.to_i).abs > Nonce.skew nonce = [server_url, timestamp, salt].join('') return false if @nonces[nonce] @nonces[nonce] = timestamp return true end def cleanup_associations count = 0 @associations.each{|server_url, assocs| assocs.each{|handle, assoc| if assoc.expires_in == 0 assocs.delete(handle) count += 1 end } } return count end def cleanup_nonces count = 0 now = Time.now.to_i @nonces.each{|nonce, timestamp| if (timestamp - now).abs > Nonce.skew @nonces.delete(nonce) count += 1 end } return count end protected def deepcopy(o) Marshal.load(Marshal.dump(o)) end end end end ruby-openid-2.7.0debian.orig/lib/openid/store/interface.rb0000644000175000017500000000575512512544714022775 0ustar sbadiasbadiarequire 'openid/util' module OpenID # Stores for Associations and nonces. Used by both the Consumer and # the Server. If you have a database abstraction layer or other # state storage in your application or framework already, you can # implement the store interface. module Store # Abstract Store # Changes in 2.0: # * removed store_nonce, get_auth_key, is_dumb # * changed use_nonce to support one-way nonces # * added cleanup_nonces, cleanup_associations, cleanup class Interface < Object # Put a Association object into storage. # When implementing a store, don't assume that there are any limitations # on the character set of the server_url. In particular, expect to see # unescaped non-url-safe characters in the server_url field. def store_association(server_url, association) raise NotImplementedError end # Returns a Association object from storage that matches # the server_url. Returns nil if no such association is found or if # the one matching association is expired. (Is allowed to GC expired # associations when found.) def get_association(server_url, handle=nil) raise NotImplementedError end # If there is a matching association, remove it from the store and # return true, otherwise return false. def remove_association(server_url, handle) raise NotImplementedError end # Return true if the nonce has not been used before, and store it # for a while to make sure someone doesn't try to use the same value # again. Return false if the nonce has already been used or if the # timestamp is not current. # You can use OpenID::Store::Nonce::SKEW for your timestamp window. # server_url: URL of the server from which the nonce originated # timestamp: time the nonce was created in seconds since unix epoch # salt: A random string that makes two nonces issued by a server in # the same second unique def use_nonce(server_url, timestamp, salt) raise NotImplementedError end # Remove expired nonces from the store # Discards any nonce that is old enough that it wouldn't pass use_nonce # Not called during normal library operation, this method is for store # admins to keep their storage from filling up with expired data def cleanup_nonces raise NotImplementedError end # Remove expired associations from the store # Not called during normal library operation, this method is for store # admins to keep their storage from filling up with expired data def cleanup_associations raise NotImplementedError end # Remove expired nonces and associations from the store # Not called during normal library operation, this method is for store # admins to keep their storage from filling up with expired data def cleanup return cleanup_nonces, cleanup_associations end end end end ruby-openid-2.7.0debian.orig/lib/openid/store/memcache.rb0000644000175000017500000000713512512544714022571 0ustar sbadiasbadiarequire 'openid/util' require 'openid/store/interface' require 'openid/store/nonce' require 'time' module OpenID module Store class Memcache < Interface attr_accessor :key_prefix def initialize(cache_client, key_prefix='openid-store:') @cache_client = cache_client self.key_prefix = key_prefix end # Put a Association object into storage. # When implementing a store, don't assume that there are any limitations # on the character set of the server_url. In particular, expect to see # unescaped non-url-safe characters in the server_url field. def store_association(server_url, association) serialized = serialize(association) [nil, association.handle].each do |handle| key = assoc_key(server_url, handle) @cache_client.set(key, serialized, expiry(association.lifetime)) end end # Returns a Association object from storage that matches # the server_url. Returns nil if no such association is found or if # the one matching association is expired. (Is allowed to GC expired # associations when found.) def get_association(server_url, handle=nil) serialized = @cache_client.get(assoc_key(server_url, handle)) if serialized return deserialize(serialized) else return nil end end # If there is a matching association, remove it from the store and # return true, otherwise return false. def remove_association(server_url, handle) deleted = delete(assoc_key(server_url, handle)) server_assoc = get_association(server_url) if server_assoc && server_assoc.handle == handle deleted = delete(assoc_key(server_url)) | deleted end return deleted end # Return true if the nonce has not been used before, and store it # for a while to make sure someone doesn't try to use the same value # again. Return false if the nonce has already been used or if the # timestamp is not current. # You can use OpenID::Store::Nonce::SKEW for your timestamp window. # server_url: URL of the server from which the nonce originated # timestamp: time the nonce was created in seconds since unix epoch # salt: A random string that makes two nonces issued by a server in # the same second unique def use_nonce(server_url, timestamp, salt) return false if (timestamp - Time.now.to_i).abs > Nonce.skew ts = timestamp.to_s # base 10 seconds since epoch nonce_key = key_prefix + 'N' + server_url + '|' + ts + '|' + salt result = @cache_client.add(nonce_key, '', expiry(Nonce.skew + 5)) if result.is_a? String return !!(result =~ /^STORED/) else return !!(result) end end def assoc_key(server_url, assoc_handle=nil) key = key_prefix + 'A' + server_url if assoc_handle key += '|' + assoc_handle end return key end def cleanup_nonces end def cleanup end def cleanup_associations end protected def delete(key) result = @cache_client.delete(key) if result.is_a? String return !!(result =~ /^DELETED/) else return !!(result) end end def serialize(assoc) Marshal.dump(assoc) end def deserialize(assoc_str) Marshal.load(assoc_str) end # Convert a lifetime in seconds into a memcache expiry value def expiry(t) Time.now.to_i + t end end end end ruby-openid-2.7.0debian.orig/lib/openid/store/filesystem.rb0000644000175000017500000001606312512544714023213 0ustar sbadiasbadiarequire 'fileutils' require 'pathname' require 'tempfile' require 'openid/util' require 'openid/store/interface' require 'openid/association' module OpenID module Store class Filesystem < Interface @@FILENAME_ALLOWED = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-".split("") # Create a Filesystem store instance, putting all data in +directory+. def initialize(directory) @nonce_dir = File.join(directory, 'nonces') @association_dir = File.join(directory, 'associations') @temp_dir = File.join(directory, 'temp') self.ensure_dir(@nonce_dir) self.ensure_dir(@association_dir) self.ensure_dir(@temp_dir) end # Create a unique filename for a given server url and handle. The # filename that is returned will contain the domain name from the # server URL for ease of human inspection of the data dir. def get_association_filename(server_url, handle) unless server_url.index('://') raise ArgumentError, "Bad server URL: #{server_url}" end proto, rest = server_url.split('://', 2) domain = filename_escape(rest.split('/',2)[0]) url_hash = safe64(server_url) if handle handle_hash = safe64(handle) else handle_hash = '' end filename = [proto,domain,url_hash,handle_hash].join('-') File.join(@association_dir, filename) end # Store an association in the assoc directory def store_association(server_url, association) assoc_s = association.serialize filename = get_association_filename(server_url, association.handle) f, tmp = mktemp begin begin f.write(assoc_s) f.fsync ensure f.close end begin File.rename(tmp, filename) rescue Errno::EEXIST begin File.unlink(filename) rescue Errno::ENOENT # do nothing end File.rename(tmp, filename) end rescue self.remove_if_present(tmp) raise end end # Retrieve an association def get_association(server_url, handle=nil) # the filename with empty handle is the prefix for the associations # for a given server url filename = get_association_filename(server_url, handle) if handle return _get_association(filename) end assoc_filenames = Dir.glob(filename.to_s + '*') assocs = assoc_filenames.collect do |f| _get_association(f) end assocs = assocs.find_all { |a| not a.nil? } assocs = assocs.sort_by { |a| a.issued } return nil if assocs.empty? return assocs[-1] end def _get_association(filename) begin assoc_file = File.open(filename, "r") rescue Errno::ENOENT return nil else begin assoc_s = assoc_file.read ensure assoc_file.close end begin association = Association.deserialize(assoc_s) rescue self.remove_if_present(filename) return nil end # clean up expired associations if association.expires_in == 0 self.remove_if_present(filename) return nil else return association end end end # Remove an association if it exists, otherwise do nothing. def remove_association(server_url, handle) assoc = get_association(server_url, handle) if assoc.nil? return false else filename = get_association_filename(server_url, handle) return self.remove_if_present(filename) end end # Return whether the nonce is valid def use_nonce(server_url, timestamp, salt) return false if (timestamp - Time.now.to_i).abs > Nonce.skew if server_url and !server_url.empty? proto, rest = server_url.split('://',2) else proto, rest = '','' end raise "Bad server URL" unless proto && rest domain = filename_escape(rest.split('/',2)[0]) url_hash = safe64(server_url) salt_hash = safe64(salt) nonce_fn = '%08x-%s-%s-%s-%s'%[timestamp, proto, domain, url_hash, salt_hash] filename = File.join(@nonce_dir, nonce_fn) begin fd = File.new(filename, File::CREAT | File::EXCL | File::WRONLY, 0200) fd.close return true rescue Errno::EEXIST return false end end # Remove expired entries from the database. This is potentially expensive, # so only run when it is acceptable to take time. def cleanup cleanup_associations cleanup_nonces end def cleanup_associations association_filenames = Dir[File.join(@association_dir, "*")] count = 0 association_filenames.each do |af| begin f = File.open(af, 'r') rescue Errno::ENOENT next else begin assoc_s = f.read ensure f.close end begin association = OpenID::Association.deserialize(assoc_s) rescue StandardError self.remove_if_present(af) next else if association.expires_in == 0 self.remove_if_present(af) count += 1 end end end end return count end def cleanup_nonces nonces = Dir[File.join(@nonce_dir, "*")] now = Time.now.to_i count = 0 nonces.each do |filename| nonce = filename.split('/')[-1] timestamp = nonce.split('-', 2)[0].to_i(16) nonce_age = (timestamp - now).abs if nonce_age > Nonce.skew self.remove_if_present(filename) count += 1 end end return count end protected # Create a temporary file and return the File object and filename. def mktemp f = Tempfile.new('tmp', @temp_dir) [f, f.path] end # create a safe filename from a url def filename_escape(s) s = '' if s.nil? filename_chunks = s.each_char.flat_map {|c| @@FILENAME_ALLOWED.include?(c) ? c : c.bytes.map {|b| "_%02X" % b } }.join end def safe64(s) s = OpenID::CryptUtil.sha1(s) s = OpenID::Util.to_base64(s) s.gsub!('+', '_') s.gsub!('/', '.') s.gsub!('=', '') return s end # remove file if present in filesystem def remove_if_present(filename) begin File.unlink(filename) rescue Errno::ENOENT return false end return true end # ensure that a path exists def ensure_dir(dir_name) FileUtils::mkdir_p(dir_name) end end end end ruby-openid-2.7.0debian.orig/lib/openid/dh.rb0000644000175000017500000000524612512544714020267 0ustar sbadiasbadiarequire "openid/util" require "openid/cryptutil" module OpenID # Encapsulates a Diffie-Hellman key exchange. This class is used # internally by both the consumer and server objects. # # Read more about Diffie-Hellman on wikipedia: # http://en.wikipedia.org/wiki/Diffie-Hellman class DiffieHellman # From the OpenID specification @@default_mod = 155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443 @@default_gen = 2 attr_reader :modulus, :generator, :public # A new DiffieHellman object, using the modulus and generator from # the OpenID specification def DiffieHellman.from_defaults DiffieHellman.new(@@default_mod, @@default_gen) end def initialize(modulus=nil, generator=nil, priv=nil) @modulus = modulus.nil? ? @@default_mod : modulus @generator = generator.nil? ? @@default_gen : generator set_private(priv.nil? ? OpenID::CryptUtil.rand(@modulus-2) + 1 : priv) end def get_shared_secret(composite) DiffieHellman.powermod(composite, @private, @modulus) end def xor_secret(algorithm, composite, secret) dh_shared = get_shared_secret(composite) packed_dh_shared = OpenID::CryptUtil.num_to_binary(dh_shared) hashed_dh_shared = algorithm.call(packed_dh_shared) return DiffieHellman.strxor(secret, hashed_dh_shared) end def using_default_values? @generator == @@default_gen && @modulus == @@default_mod end private def set_private(priv) @private = priv @public = DiffieHellman.powermod(@generator, @private, @modulus) end def DiffieHellman.strxor(s, t) if s.length != t.length raise ArgumentError, "strxor: lengths don't match. " + "Inputs were #{s.inspect} and #{t.inspect}" end if String.method_defined? :bytes s.bytes.to_a.zip(t.bytes.to_a).map{|sb,tb| sb^tb}.pack('C*') else indices = 0...(s.length) chrs = indices.collect {|i| (s[i]^t[i]).chr} chrs.join("") end end # This code is taken from this post: # # by Eric Lee Green. def DiffieHellman.powermod(x, n, q) counter=0 n_p=n y_p=1 z_p=x while n_p != 0 if n_p[0]==1 y_p=(y_p*z_p) % q end n_p = n_p >> 1 z_p = (z_p * z_p) % q counter += 1 end return y_p end end end ruby-openid-2.7.0debian.orig/lib/openid/trustroot.rb0000644000175000017500000002522612512544714021761 0ustar sbadiasbadiarequire 'uri' require 'openid/urinorm' module OpenID class RealmVerificationRedirected < Exception # Attempting to verify this realm resulted in a redirect. def initialize(relying_party_url, rp_url_after_redirects) @relying_party_url = relying_party_url @rp_url_after_redirects = rp_url_after_redirects end def to_s return "Attempting to verify #{@relying_party_url} resulted in " + "redirect to #{@rp_url_after_redirects}" end end module TrustRoot TOP_LEVEL_DOMAINS = %w' ac ad ae aero af ag ai al am an ao aq ar arpa as asia at au aw ax az ba bb bd be bf bg bh bi biz bj bm bn bo br bs bt bv bw by bz ca cat cc cd cf cg ch ci ck cl cm cn co com coop cr cu cv cx cy cz de dj dk dm do dz ec edu ee eg er es et eu fi fj fk fm fo fr ga gb gd ge gf gg gh gi gl gm gn gov gp gq gr gs gt gu gw gy hk hm hn hr ht hu id ie il im in info int io iq ir is it je jm jo jobs jp ke kg kh ki km kn kp kr kw ky kz la lb lc li lk lr ls lt lu lv ly ma mc md me mg mh mil mk ml mm mn mo mobi mp mq mr ms mt mu museum mv mw mx my mz na name nc ne net nf ng ni nl no np nr nu nz om org pa pe pf pg ph pk pl pm pn pr pro ps pt pw py qa re ro rs ru rw sa sb sc sd se sg sh si sj sk sl sm sn so sr st su sv sy sz tc td tel tf tg th tj tk tl tm tn to tp tr travel tt tv tw tz ua ug uk us uy uz va vc ve vg vi vn vu wf ws xn--0zwm56d xn--11b5bs3a9aj6g xn--80akhbyknj4f xn--9t4b11yi5a xn--deba0ad xn--g6w251d xn--hgbk6aj7f53bba xn--hlcj6aya9esc7a xn--jxalpdlp xn--kgbechtv xn--zckzah ye yt yu za zm zw' ALLOWED_PROTOCOLS = ['http', 'https'] # The URI for relying party discovery, used in realm verification. # # XXX: This should probably live somewhere else (like in # OpenID or OpenID::Yadis somewhere) RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to' # If the endpoint is a relying party OpenID return_to endpoint, # return the endpoint URL. Otherwise, return None. # # This function is intended to be used as a filter for the Yadis # filtering interface. # # endpoint: An XRDS BasicServiceEndpoint, as returned by # performing Yadis dicovery. # # returns the endpoint URL or None if the endpoint is not a # relying party endpoint. def TrustRoot._extract_return_url(endpoint) if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE]) return endpoint.uri else return nil end end # Is the return_to URL under one of the supplied allowed # return_to URLs? def TrustRoot.return_to_matches(allowed_return_to_urls, return_to) allowed_return_to_urls.each { |allowed_return_to| # A return_to pattern works the same as a realm, except that # it's not allowed to use a wildcard. We'll model this by # parsing it as a realm, and not trying to match it if it has # a wildcard. return_realm = TrustRoot.parse(allowed_return_to) if (# Parses as a trust root !return_realm.nil? and # Does not have a wildcard !return_realm.wildcard and # Matches the return_to that we passed in with it return_realm.validate_url(return_to) ) return true end } # No URL in the list matched return false end # Given a relying party discovery URL return a list of return_to # URLs. def TrustRoot.get_allowed_return_urls(relying_party_url) rp_url_after_redirects, return_to_urls = services.get_service_endpoints( relying_party_url, _extract_return_url) if rp_url_after_redirects != relying_party_url # Verification caused a redirect raise RealmVerificationRedirected.new( relying_party_url, rp_url_after_redirects) end return return_to_urls end # Verify that a return_to URL is valid for the given realm. # # This function builds a discovery URL, performs Yadis discovery # on it, makes sure that the URL does not redirect, parses out # the return_to URLs, and finally checks to see if the current # return_to URL matches the return_to. # # raises DiscoveryFailure when Yadis discovery fails returns # true if the return_to URL is valid for the realm def TrustRoot.verify_return_to(realm_str, return_to, _vrfy=nil) # _vrfy parameter is there to make testing easier if _vrfy.nil? _vrfy = self.method('get_allowed_return_urls') end if !(_vrfy.is_a?(Proc) or _vrfy.is_a?(Method)) raise ArgumentError, "_vrfy must be a Proc or Method" end realm = TrustRoot.parse(realm_str) if realm.nil? # The realm does not parse as a URL pattern return false end begin allowable_urls = _vrfy.call(realm.build_discovery_url()) rescue RealmVerificationRedirected => err Util.log(err.to_s) return false end if return_to_matches(allowable_urls, return_to) return true else Util.log("Failed to validate return_to #{return_to} for " + "realm #{realm_str}, was not in #{allowable_urls}") return false end end class TrustRoot attr_reader :unparsed, :proto, :wildcard, :host, :port, :path @@empty_re = Regexp.new('^http[s]*:\/\/\*\/$') def TrustRoot._build_path(path, query=nil, frag=nil) s = path.dup frag = nil if frag == '' query = nil if query == '' if query s << "?" << query end if frag s << "#" << frag end return s end def TrustRoot._parse_url(url) begin url = URINorm.urinorm(url) rescue URI::InvalidURIError nil end begin parsed = URI::DEFAULT_PARSER.parse(url) rescue URI::InvalidURIError return nil end path = TrustRoot._build_path(parsed.path, parsed.query, parsed.fragment) return [parsed.scheme || '', parsed.host || '', parsed.port || '', path || ''] end def TrustRoot.parse(trust_root) trust_root = trust_root.dup unparsed = trust_root.dup # look for wildcard wildcard = (not trust_root.index('://*.').nil?) trust_root.sub!('*.', '') if wildcard # handle http://*/ case if not wildcard and @@empty_re.match(trust_root) proto = trust_root.split(':')[0] port = proto == 'http' ? 80 : 443 return new(unparsed, proto, true, '', port, '/') end parts = TrustRoot._parse_url(trust_root) return nil if parts.nil? proto, host, port, path = parts return nil if host[0] == '.' # check for URI fragment if path and !path.index('#').nil? return nil end return nil unless ['http', 'https'].member?(proto) return new(unparsed, proto, wildcard, host, port, path) end def TrustRoot.check_sanity(trust_root_string) trust_root = TrustRoot.parse(trust_root_string) if trust_root.nil? return false else return trust_root.sane? end end # quick func for validating a url against a trust root. See the # TrustRoot class if you need more control. def self.check_url(trust_root, url) tr = self.parse(trust_root) return (!tr.nil? and tr.validate_url(url)) end # Return a discovery URL for this realm. # # This function does not check to make sure that the realm is # valid. Its behaviour on invalid inputs is undefined. # # return_to:: The relying party return URL of the OpenID # authentication request # # Returns the URL upon which relying party discovery should be # run in order to verify the return_to URL def build_discovery_url if self.wildcard # Use "www." in place of the star www_domain = 'www.' + @host port = (!@port.nil? and ![80, 443].member?(@port)) ? (":" + @port.to_s) : '' return "#{@proto}://#{www_domain}#{port}#{@path}" else return @unparsed end end def initialize(unparsed, proto, wildcard, host, port, path) @unparsed = unparsed @proto = proto @wildcard = wildcard @host = host @port = port @path = path end def sane? return true if @host == 'localhost' host_parts = @host.split('.') # a note: ruby string split does not put an empty string at # the end of the list if the split element is last. for # example, 'foo.com.'.split('.') => ['foo','com']. Mentioned # because the python code differs here. return false if host_parts.length == 0 # no adjacent dots return false if host_parts.member?('') # last part must be a tld tld = host_parts[-1] return false unless TOP_LEVEL_DOMAINS.member?(tld) return false if host_parts.length == 1 if @wildcard if tld.length == 2 and host_parts[-2].length <= 3 # It's a 2-letter tld with a short second to last segment # so there needs to be more than two segments specified # (e.g. *.co.uk is insane) return host_parts.length > 2 end end return true end def validate_url(url) parts = TrustRoot._parse_url(url) return false if parts.nil? proto, host, port, path = parts return false unless proto == @proto return false unless port == @port return false unless host.index('*').nil? if !@wildcard if host != @host return false end elsif ((@host != '') and (!host.end_with?('.' + @host)) and (host != @host)) return false end if path != @path path_len = @path.length trust_prefix = @path[0...path_len] url_prefix = path[0...path_len] # must be equal up to the length of the path, at least if trust_prefix != url_prefix return false end # These characters must be on the boundary between the end # of the trust root's path and the start of the URL's path. if !@path.index('?').nil? allowed = '&' else allowed = '?/' end return (!allowed.index(@path[-1]).nil? or !allowed.index(path[path_len]).nil?) end return true end end end end ruby-openid-2.7.0debian.orig/lib/openid.rb0000644000175000017500000000124312512544714017665 0ustar sbadiasbadia# Copyright 2006-2007 JanRain, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You may # obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. module OpenID end require 'openid/version' require 'openid/consumer' require 'openid/server' ruby-openid-2.7.0debian.orig/metadata.yml0000644000175000017500000002652512512544714017631 0ustar sbadiasbadia--- !ruby/object:Gem::Specification name: ruby-openid version: !ruby/object:Gem::Version version: 2.7.0 platform: ruby authors: - JanRain, Inc autorequire: openid bindir: bin cert_chain: [] date: 2015-03-05 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: minitest requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '5' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '5' description: email: openid@janrain.com executables: [] extensions: [] extra_rdoc_files: - README.md - INSTALL.md - LICENSE - UPGRADE.md files: - CHANGELOG.md - INSTALL.md - LICENSE - NOTICE - README.md - UPGRADE.md - examples/README - examples/active_record_openid_store/README - examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb - examples/active_record_openid_store/XXX_upgrade_open_id_store.rb - examples/active_record_openid_store/init.rb - examples/active_record_openid_store/lib/association.rb - examples/active_record_openid_store/lib/nonce.rb - examples/active_record_openid_store/lib/open_id_setting.rb - examples/active_record_openid_store/lib/openid_ar_store.rb - examples/active_record_openid_store/test/store_test.rb - examples/discover - examples/rails_openid/Gemfile - examples/rails_openid/README - examples/rails_openid/README.rdoc - examples/rails_openid/Rakefile - examples/rails_openid/app/assets/images/rails.png - examples/rails_openid/app/assets/javascripts/application.js - examples/rails_openid/app/assets/stylesheets/application.css - examples/rails_openid/app/controllers/application_controller.rb - examples/rails_openid/app/controllers/consumer_controller.rb - examples/rails_openid/app/controllers/login_controller.rb - examples/rails_openid/app/controllers/server_controller.rb - examples/rails_openid/app/helpers/application_helper.rb - examples/rails_openid/app/helpers/login_helper.rb - examples/rails_openid/app/helpers/server_helper.rb - examples/rails_openid/app/views/consumer/index.html.erb - examples/rails_openid/app/views/layouts/server.html.erb - examples/rails_openid/app/views/login/index.html.erb - examples/rails_openid/app/views/server/decide.html.erb - examples/rails_openid/config.ru - examples/rails_openid/config/application.rb - examples/rails_openid/config/boot.rb - examples/rails_openid/config/database.yml - examples/rails_openid/config/environment.rb - examples/rails_openid/config/environments/development.rb - examples/rails_openid/config/environments/production.rb - examples/rails_openid/config/environments/test.rb - examples/rails_openid/config/initializers/backtrace_silencers.rb - examples/rails_openid/config/initializers/inflections.rb - examples/rails_openid/config/initializers/mime_types.rb - examples/rails_openid/config/initializers/rails_root.rb - examples/rails_openid/config/initializers/secret_token.rb - examples/rails_openid/config/initializers/session_store.rb - examples/rails_openid/config/initializers/wrap_parameters.rb - examples/rails_openid/config/locales/en.yml - examples/rails_openid/config/routes.rb - examples/rails_openid/db/development.sqlite3 - examples/rails_openid/db/seeds.rb - examples/rails_openid/doc/README_FOR_APP - examples/rails_openid/log/development.log - examples/rails_openid/public/404.html - examples/rails_openid/public/422.html - examples/rails_openid/public/500.html - examples/rails_openid/public/dispatch.cgi - examples/rails_openid/public/dispatch.fcgi - examples/rails_openid/public/dispatch.rb - examples/rails_openid/public/favicon.ico - examples/rails_openid/public/images/openid_login_bg.gif - examples/rails_openid/public/javascripts/application.js - examples/rails_openid/public/javascripts/controls.js - examples/rails_openid/public/javascripts/dragdrop.js - examples/rails_openid/public/javascripts/effects.js - examples/rails_openid/public/javascripts/prototype.js - examples/rails_openid/public/robots.txt - examples/rails_openid/script/rails - examples/rails_openid/test/functional/login_controller_test.rb - examples/rails_openid/test/functional/server_controller_test.rb - examples/rails_openid/test/performance/browsing_test.rb - examples/rails_openid/test/test_helper.rb - lib/hmac/hmac.rb - lib/hmac/sha1.rb - lib/hmac/sha2.rb - lib/openid.rb - lib/openid/association.rb - lib/openid/consumer.rb - lib/openid/consumer/associationmanager.rb - lib/openid/consumer/checkid_request.rb - lib/openid/consumer/discovery.rb - lib/openid/consumer/discovery_manager.rb - lib/openid/consumer/html_parse.rb - lib/openid/consumer/idres.rb - lib/openid/consumer/responses.rb - lib/openid/consumer/session.rb - lib/openid/cryptutil.rb - lib/openid/dh.rb - lib/openid/extension.rb - lib/openid/extensions/ax.rb - lib/openid/extensions/oauth.rb - lib/openid/extensions/pape.rb - lib/openid/extensions/sreg.rb - lib/openid/extensions/ui.rb - lib/openid/fetchers.rb - lib/openid/kvform.rb - lib/openid/kvpost.rb - lib/openid/message.rb - lib/openid/protocolerror.rb - lib/openid/server.rb - lib/openid/store/filesystem.rb - lib/openid/store/interface.rb - lib/openid/store/memcache.rb - lib/openid/store/memory.rb - lib/openid/store/nonce.rb - lib/openid/trustroot.rb - lib/openid/urinorm.rb - lib/openid/util.rb - lib/openid/version.rb - lib/openid/yadis/accept.rb - lib/openid/yadis/constants.rb - lib/openid/yadis/discovery.rb - lib/openid/yadis/filters.rb - lib/openid/yadis/htmltokenizer.rb - lib/openid/yadis/parsehtml.rb - lib/openid/yadis/services.rb - lib/openid/yadis/xrds.rb - lib/openid/yadis/xri.rb - lib/openid/yadis/xrires.rb - test/data/accept.txt - test/data/dh.txt - test/data/example-xrds.xml - test/data/linkparse.txt - test/data/n2b64 - test/data/test1-discover.txt - test/data/test1-parsehtml.txt - test/data/test_discover/malformed_meta_tag.html - test/data/test_discover/openid.html - test/data/test_discover/openid2.html - test/data/test_discover/openid2_xrds.xml - test/data/test_discover/openid2_xrds_no_local_id.xml - test/data/test_discover/openid_1_and_2.html - test/data/test_discover/openid_1_and_2_xrds.xml - test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml - test/data/test_discover/openid_and_yadis.html - test/data/test_discover/openid_no_delegate.html - test/data/test_discover/openid_utf8.html - test/data/test_discover/yadis_0entries.xml - test/data/test_discover/yadis_2_bad_local_id.xml - test/data/test_discover/yadis_2entries_delegate.xml - test/data/test_discover/yadis_2entries_idp.xml - test/data/test_discover/yadis_another_delegate.xml - test/data/test_discover/yadis_idp.xml - test/data/test_discover/yadis_idp_delegate.xml - test/data/test_discover/yadis_no_delegate.xml - test/data/test_xrds/=j3h.2007.11.14.xrds - test/data/test_xrds/README - test/data/test_xrds/delegated-20060809-r1.xrds - test/data/test_xrds/delegated-20060809-r2.xrds - test/data/test_xrds/delegated-20060809.xrds - test/data/test_xrds/no-xrd.xml - test/data/test_xrds/not-xrds.xml - test/data/test_xrds/prefixsometimes.xrds - test/data/test_xrds/ref.xrds - test/data/test_xrds/sometimesprefix.xrds - test/data/test_xrds/spoof1.xrds - test/data/test_xrds/spoof2.xrds - test/data/test_xrds/spoof3.xrds - test/data/test_xrds/status222.xrds - test/data/test_xrds/subsegments.xrds - test/data/test_xrds/valid-populated-xrds.xml - test/data/trustroot.txt - test/data/urinorm.txt - test/discoverdata.rb - test/test_accept.rb - test/test_association.rb - test/test_associationmanager.rb - test/test_ax.rb - test/test_checkid_request.rb - test/test_consumer.rb - test/test_cryptutil.rb - test/test_dh.rb - test/test_discover.rb - test/test_discovery_manager.rb - test/test_extension.rb - test/test_fetchers.rb - test/test_filters.rb - test/test_idres.rb - test/test_kvform.rb - test/test_kvpost.rb - test/test_linkparse.rb - test/test_message.rb - test/test_nonce.rb - test/test_oauth.rb - test/test_openid_yadis.rb - test/test_pape.rb - test/test_parsehtml.rb - test/test_responses.rb - test/test_server.rb - test/test_sreg.rb - test/test_stores.rb - test/test_trustroot.rb - test/test_ui.rb - test/test_urinorm.rb - test/test_util.rb - test/test_xrds.rb - test/test_xri.rb - test/test_xrires.rb - test/test_yadis_discovery.rb - test/testutil.rb - test/util.rb homepage: https://github.com/openid/ruby-openid licenses: - Ruby - Apache Software License 2.0 metadata: {} post_install_message: rdoc_options: - "--main" - README.md require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.5 signing_key: specification_version: 4 summary: A library for consuming and serving OpenID identities. test_files: - test/data/accept.txt - test/data/dh.txt - test/data/example-xrds.xml - test/data/linkparse.txt - test/data/n2b64 - test/data/test1-discover.txt - test/data/test1-parsehtml.txt - test/data/test_discover/malformed_meta_tag.html - test/data/test_discover/openid.html - test/data/test_discover/openid2.html - test/data/test_discover/openid2_xrds.xml - test/data/test_discover/openid2_xrds_no_local_id.xml - test/data/test_discover/openid_1_and_2.html - test/data/test_discover/openid_1_and_2_xrds.xml - test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml - test/data/test_discover/openid_and_yadis.html - test/data/test_discover/openid_no_delegate.html - test/data/test_discover/openid_utf8.html - test/data/test_discover/yadis_0entries.xml - test/data/test_discover/yadis_2_bad_local_id.xml - test/data/test_discover/yadis_2entries_delegate.xml - test/data/test_discover/yadis_2entries_idp.xml - test/data/test_discover/yadis_another_delegate.xml - test/data/test_discover/yadis_idp.xml - test/data/test_discover/yadis_idp_delegate.xml - test/data/test_discover/yadis_no_delegate.xml - test/data/test_xrds/=j3h.2007.11.14.xrds - test/data/test_xrds/README - test/data/test_xrds/delegated-20060809-r1.xrds - test/data/test_xrds/delegated-20060809-r2.xrds - test/data/test_xrds/delegated-20060809.xrds - test/data/test_xrds/no-xrd.xml - test/data/test_xrds/not-xrds.xml - test/data/test_xrds/prefixsometimes.xrds - test/data/test_xrds/ref.xrds - test/data/test_xrds/sometimesprefix.xrds - test/data/test_xrds/spoof1.xrds - test/data/test_xrds/spoof2.xrds - test/data/test_xrds/spoof3.xrds - test/data/test_xrds/status222.xrds - test/data/test_xrds/subsegments.xrds - test/data/test_xrds/valid-populated-xrds.xml - test/data/trustroot.txt - test/data/urinorm.txt - test/discoverdata.rb - test/test_accept.rb - test/test_association.rb - test/test_associationmanager.rb - test/test_ax.rb - test/test_checkid_request.rb - test/test_consumer.rb - test/test_cryptutil.rb - test/test_dh.rb - test/test_discover.rb - test/test_discovery_manager.rb - test/test_extension.rb - test/test_fetchers.rb - test/test_filters.rb - test/test_idres.rb - test/test_kvform.rb - test/test_kvpost.rb - test/test_linkparse.rb - test/test_message.rb - test/test_nonce.rb - test/test_oauth.rb - test/test_openid_yadis.rb - test/test_pape.rb - test/test_parsehtml.rb - test/test_responses.rb - test/test_server.rb - test/test_sreg.rb - test/test_stores.rb - test/test_trustroot.rb - test/test_ui.rb - test/test_urinorm.rb - test/test_util.rb - test/test_xrds.rb - test/test_xri.rb - test/test_xrires.rb - test/test_yadis_discovery.rb - test/testutil.rb - test/util.rb ruby-openid-2.7.0debian.orig/NOTICE0000644000175000017500000000015112512544714016215 0ustar sbadiasbadiaThis product includes software developed by JanRain, available from http://github.com/openid/ruby-openid ruby-openid-2.7.0debian.orig/README.md0000644000175000017500000000472112512544714016577 0ustar sbadiasbadia# Ruby OpenID A Ruby library for verifying and serving OpenID identities. [![Build Status](https://secure.travis-ci.org/openid/ruby-openid.png)](http://travis-ci.org/openid/ruby-openid) ## Features * Easy to use API for verifying OpenID identites - OpenID::Consumer * Support for serving OpenID identites - OpenID::Server * Does not depend on underlying web framework * Supports multiple storage mechanisms (Filesystem, ActiveRecord, Memory) * Example code to help you get started, including: * Ruby on Rails based consumer and server * OpenIDLoginGenerator for quickly getting creating a rails app that uses OpenID for authentication * ActiveRecordOpenIDStore plugin * Comprehensive test suite * Supports both OpenID 1 and OpenID 2 transparently ## Installing Before running the examples or writing your own code you'll need to install the library. See the INSTALL file or use rubygems: gem install ruby-openid Check the installation: $ irb irb> require 'rubygems' => false irb> gem 'ruby-openid' => true The library is known to work with Ruby 1.9.2 and above on Unix, Max OS X and Win32. ## Getting Started The best way to start is to look at the rails_openid example. You can run it with: cd examples/rails_openid script/server If you are writing an OpenID Relying Party, a good place to start is: `examples/rails_openid/app/controllers/consumer_controller.rb` And if you are writing an OpenID provider: `examples/rails_openid/app/controllers/server_controller.rb` The library code is quite well documented, so don't be squeamish, and look at the library itself if there's anything you don't understand in the examples. ## Homepage * [GitHub](http://github.com/openid/ruby-openid) * [Website](http://openid.net/) ## Community Discussion regarding the Ruby OpenID library and other JanRain OpenID libraries takes place on the [OpenID mailing list](http://openid.net/developers/dev-mailing-lists/). Please join this list to discuss, ask implementation questions, report bugs, etc. Also check out the openid channel on the freenode IRC network. If you have a bugfix or feature you'd like to contribute, don't hesitate to send it to us: [How to contribute](http://openidenabled.com/contribute/). ## Author Copyright 2006-2012, JanRain, Inc. Contact openid@janrain.com or visit the [OpenID channel on pibb.com](http://pibb.com/go/openid). ## License Apache Software License. For more information see the LICENSE file. ruby-openid-2.7.0debian.orig/examples/0000755000175000017500000000000012512544714017132 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/README0000644000175000017500000000232112512544714020010 0ustar sbadiasbadiaThis directory contains several examples that demonstrate use of the OpenID library. Make sure you have properly installed the library before running the examples. These examples are a great place to start in integrating OpenID into your application. ==Rails example The rails_openid contains a fully functional OpenID server and relying party, and acts as a starting point for implementing your own production rails server. You'll need the latest version of Ruby on Rails installed, and then: cd rails_openid ./script/server Open a web browser to http://localhost:3000/ and follow the instructions. The relevant code to work from when writing your Rails OpenID Relying Party is: rails_openid/app/controllers/consumer_controller.rb If you are working on an OpenID provider, check out rails_openid/app/controllers/server_controller.rb Since the library and examples are Apache-licensed, don't be shy about copy-and-paste. ==Rails ActiveRecord OpenIDStore plugin For various reasons you may want or need to deploy your ruby openid consumer/server using an SQL based store. The active_record_openid_store is a plugin that makes using an SQL based store simple. Follow the README inside the plugin's dir for usage. ruby-openid-2.7.0debian.orig/examples/rails_openid/0000755000175000017500000000000012512544714021602 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/test/0000755000175000017500000000000012512544714022561 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/test/test_helper.rb0000644000175000017500000000070612512544714025427 0ustar sbadiasbadiaENV["RAILS_ENV"] = "test" require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. # # Note: You'll currently still have to declare fixtures explicitly in integration tests # -- they do not yet inherit this setting fixtures :all # Add more helper methods to be used by all tests here... end ruby-openid-2.7.0debian.orig/examples/rails_openid/test/performance/0000755000175000017500000000000012512544714025062 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/test/performance/browsing_test.rb0000644000175000017500000000056212512544714030303 0ustar sbadiasbadiarequire 'test_helper' require 'rails/performance_test_help' class BrowsingTest < ActionDispatch::PerformanceTest # Refer to the documentation for all available options # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] # :output => 'tmp/performance', :formats => [:flat] } def test_homepage get '/' end end ruby-openid-2.7.0debian.orig/examples/rails_openid/test/functional/0000755000175000017500000000000012512544714024723 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/test/functional/login_controller_test.rb0000644000175000017500000000073612512544714031670 0ustar sbadiasbadiarequire File.dirname(__FILE__) + '/../test_helper' require 'login_controller' # Re-raise errors caught by the controller. class LoginController; def rescue_action(e) raise e end; end class LoginControllerTest < Test::Unit::TestCase def setup @controller = LoginController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end # Replace this with your real tests. def test_truth assert true end end ruby-openid-2.7.0debian.orig/examples/rails_openid/test/functional/server_controller_test.rb0000644000175000017500000000074212512544714032063 0ustar sbadiasbadiarequire File.dirname(__FILE__) + '/../test_helper' require 'server_controller' # Re-raise errors caught by the controller. class ServerController; def rescue_action(e) raise e end; end class ServerControllerTest < Test::Unit::TestCase def setup @controller = ServerController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end # Replace this with your real tests. def test_truth assert true end end ruby-openid-2.7.0debian.orig/examples/rails_openid/script/0000755000175000017500000000000012512544714023106 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/script/rails0000755000175000017500000000044712512544714024153 0ustar sbadiasbadia#!/usr/bin/env ruby # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. APP_PATH = File.expand_path('../../config/application', __FILE__) require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' ruby-openid-2.7.0debian.orig/examples/rails_openid/config.ru0000644000175000017500000000024112512544714023414 0ustar sbadiasbadia# This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) run RailsOpenid::Application ruby-openid-2.7.0debian.orig/examples/rails_openid/README0000644000175000017500000001366012512544714022470 0ustar sbadiasbadia== Welcome to Rails Rails is a web-application and persistence framework that includes everything needed to create database-backed web-applications according to the Model-View-Control pattern of separation. This pattern splits the view (also called the presentation) into "dumb" templates that are primarily responsible for inserting pre-built data in between HTML tags. The model contains the "smart" domain objects (such as Account, Product, Person, Post) that holds all the business logic and knows how to persist themselves to a database. The controller handles the incoming requests (such as Save New Account, Update Product, Show Post) by manipulating the model and directing data to the view. In Rails, the model is handled by what's called an object-relational mapping layer entitled Active Record. This layer allows you to present the data from database rows as objects and embellish these data objects with business logic methods. You can read more about Active Record in link:files/vendor/rails/activerecord/README.html. The controller and view are handled by the Action Pack, which handles both layers by its two parts: Action View and Action Controller. These two layers are bundled in a single package due to their heavy interdependence. This is unlike the relationship between the Active Record and Action Pack that is much more separate. Each of these packages can be used independently outside of Rails. You can read more about Action Pack in link:files/vendor/rails/actionpack/README.html. == Getting started 1. Run the WEBrick servlet: ruby script/server (run with --help for options) ...or if you have lighttpd installed: ruby script/lighttpd (it's faster) 2. Go to http://localhost:3000/ and get "Congratulations, you've put Ruby on Rails!" 3. Follow the guidelines on the "Congratulations, you've put Ruby on Rails!" screen == Example for Apache conf ServerName rails DocumentRoot /path/application/public/ ErrorLog /path/application/log/server.log Options ExecCGI FollowSymLinks AllowOverride all Allow from all Order allow,deny NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI should be on and ".cgi" should respond. All requests from 127.0.0.1 go through CGI, so no Apache restart is necessary for changes. All other requests go through FCGI (or mod_ruby), which requires a restart to show changes. == Debugging Rails Have "tail -f" commands running on both the server.log, production.log, and test.log files. Rails will automatically display debugging and runtime information to these files. Debugging info will also be shown in the browser on requests from 127.0.0.1. == Breakpoints Breakpoint support is available through the script/breakpointer client. This means that you can break out of execution at any point in the code, investigate and change the model, AND then resume execution! Example: class WeblogController < ActionController::Base def index @posts = Post.find_all breakpoint "Breaking out from the list" end end So the controller will accept the action, run the first line, then present you with a IRB prompt in the breakpointer window. Here you can do things like: Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint' >> @posts.inspect => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>, #\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" >> @posts.first.title = "hello from a breakpoint" => "hello from a breakpoint" ...and even better is that you can examine how your runtime objects actually work: >> f = @posts.first => #nil, "body"=>nil, "id"=>"1"}> >> f. Display all 152 possibilities? (y or n) Finally, when you're ready to resume execution, you press CTRL-D == Console You can interact with the domain model by starting the console through script/console. Here you'll have all parts of the application configured, just like it is when the application is running. You can inspect domain models, change values, and save to the database. Starting the script without arguments will launch it in the development environment. Passing an argument will specify a different environment, like console production. == Description of contents app Holds all the code that's specific to this particular application. app/controllers Holds controllers that should be named like weblog_controller.rb for automated URL mapping. All controllers should descend from ActionController::Base. app/models Holds models that should be named like post.rb. Most models will descend from ActiveRecord::Base. app/views Holds the template files for the view that should be named like weblog/index.rhtml for the WeblogController#index action. All views use eRuby syntax. This directory can also be used to keep stylesheets, images, and so on that can be symlinked to public. app/helpers Holds view helpers that should be named like weblog_helper.rb. config Configuration files for the Rails environment, the routing map, the database, and other dependencies. components Self-contained mini-applications that can bundle together controllers, models, and views. lib Application specific libraries. Basically, any kind of custom code that doesn't belong under controllers, models, or helpers. This directory is in the load path. public The directory available for the web server. Contains subdirectories for images, stylesheets, and javascripts. Also contains the dispatchers and the default HTML files. script Helper scripts for automation and generation. test Unit and functional tests along with fixtures. vendor External libraries that the application depends on. Also includes the plugins subdirectory. This directory is in the load path. ruby-openid-2.7.0debian.orig/examples/rails_openid/app/0000755000175000017500000000000012512544714022362 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/helpers/0000755000175000017500000000000012512544714024024 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/helpers/application_helper.rb0000644000175000017500000000003512512544714030211 0ustar sbadiasbadiamodule ApplicationHelper end ruby-openid-2.7.0debian.orig/examples/rails_openid/app/helpers/server_helper.rb0000644000175000017500000000016612512544714027221 0ustar sbadiasbadia module ServerHelper def url_for_user url_for :controller => 'user', :action => session[:username] end end ruby-openid-2.7.0debian.orig/examples/rails_openid/app/helpers/login_helper.rb0000644000175000017500000000002712512544714027017 0ustar sbadiasbadiamodule LoginHelper end ruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/0000755000175000017500000000000012512544714023517 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/consumer/0000755000175000017500000000000012512544714025352 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/consumer/index.html.erb0000644000175000017500000000451312512544714030121 0ustar sbadiasbadia Rails OpenID Example Relying Party

Rails OpenID Example Relying Party

<% if flash[:alert] %>
<%= h(flash[:alert]) %>
<% end %> <% if flash[:error] %>
<%= h(flash[:error]) %>
<% end %> <% if flash[:success] %>
<%= h(flash[:success]) %>
<% end %> <% if flash[:sreg_results] %>
<%= flash[:sreg_results] %>
<% end %> <% if flash[:pape_results] %>
<%= flash[:pape_results] %>
<% end %>
'> Identifier:



ruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/login/0000755000175000017500000000000012512544714024627 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/login/index.html.erb0000644000175000017500000000341012512544714027371 0ustar sbadiasbadia <% if session[:username].nil? %>
Type a username:
<% end %>

Welcome to the Ruby OpenID example. This code is a starting point for developers wishing to implement an OpenID provider or relying party. We've used the Rails platform to demonstrate, but the library code is not Rails specific.

To use the example provider

  1. Enter a username in the form above. You will be "Logged In" to the server, at which point you may authenticate using an OpenID consumer. Your OpenID URL will be displayed after you log in.

    The server will automatically create an identity page for you at <%= @base_url %>user/name

  2. Because WEBrick can only handle one thing at a time, you'll need to run another instance of the example on another port if you want to use a relying party to use with this example provider:

    script/server --port=3001

    (The RP needs to be able to access the provider, so unless you're running this example on a public IP, you can't use the live example at openidenabled.com on your local provider.)

  3. Point your browser to this new instance and follow the directions below.

To use the example relying party

Visit /consumer and enter your OpenID.

ruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/layouts/0000755000175000017500000000000012512544714025217 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/layouts/server.html.erb0000644000175000017500000000272012512544714030163 0ustar sbadiasbadia OpenID Server Example <%#= csrf_meta_tags %> <% if session[:username] %>
Welcome, <%= session[:username] %> | <%= link_to('Log out', :controller => 'login', :action => 'logout') %>
<%= @base_url %>user/<%= session[:username] %>
<% end %>

Ruby OpenID Server Example


<% if flash[:notice] or flash[:error] %>
<%= flash[:error] or flash[:notice] %>
<% end %> <%= yield %> ruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/server/0000755000175000017500000000000012512544714025025 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/views/server/decide.html.erb0000644000175000017500000000145012512544714027677 0ustar sbadiasbadia
<% if @oidreq.id_select %> <% else %> <% end %>
Site:<%= @oidreq.trust_root %>
You entered the server identifier at the relying party. You'll need to send an identifier of your choosing. Enter a username below.
Identity to send:
Identity:<%= @oidreq.identity %>
ruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/0000755000175000017500000000000012512544714023664 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/javascripts/0000755000175000017500000000000012512544714026215 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/javascripts/application.js0000644000175000017500000000120112512544714031050 0ustar sbadiasbadia// This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // the compiled file. // // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. // //= require jquery //= require jquery_ujs //= require_tree . ruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/stylesheets/0000755000175000017500000000000012512544714026240 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/stylesheets/application.css0000644000175000017500000000104212512544714031252 0ustar sbadiasbadia/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the top of the * compiled file, but it's generally better to create a new file per style scope. * *= require_self *= require_tree . */ ruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/images/0000755000175000017500000000000012512544714025131 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/app/assets/images/rails.png0000644000175000017500000001476612512544714026767 0ustar sbadiasbadiaPNG  IHDR2@X${tEXtSoftwareAdobe ImageReadyqe<IDATxڬ[ \eR֮^;Iwga@`gGgDgtqDFqFDqF@NRU]˫|_-Qy^Ǹ.݋0W_6kbf̻ܸ6<4 w5~*r?9m&"M7@vm' {_S)Vi\WG?իjMd@ lDLX鸺W-TU+@EPo\&*Rnn, fDWrX|3M=\EJB[d6A'=tx^$a86̈{, ϱPepN*_W_3o;ޥ(0E:i6eXnhGf"L|S+(+.gФg=Ych=m#V_#}Ǫ|tR D8VՄM~xg!ni%Dy( B,{(Np$3iر$h.@e[a'eJԂyϠ4>H*MHQ(Jgt-֢QI ^d„@s-'- 51{'0 |n4ۉh{V@ܩw"BT =rzqPpBHȃ?ň ]-qpgsPiSӪg`jn)m 御B2L.x!jJP! K/\ ʮRB[09Trӈu. uH$ DDQ+:ݘٻ 3/nލ%Sjm2!&D/[EHwW A-RR!PeuHim"t6lFgЫ-O.1?ƞksX~VtmZJR11Nu&<⽩,Tb,`w WPx-G5 `մ/5pbAtIVJ_]0/DiH=ô#*77-3 VuQ0.pݔ%yw hљW0),2$b6&I/@bj$I(fx' JnO"`<-/LѮ%^ȫͶn2wҗ2}}XսL'Q-,m/ꤋ4#0Q&00NKrsA,Aײ)aIEC(ERK{8Ȭ[y?iI5$%f{}u F 1~;v1l'@F 'IF'm!K7"&]w 15#4Vižn[v 8Ě)>C=LBo~/3% wF4֓ʿ8>bWX@bb@IzP9IvFfQL!2cEP(se4~5RhAŽ90_? cMEteVOaOr B]pȱؓ"Eyx: NJ)bl׋hYuTdԫw=آMgwVPOFΒ25-TD[Z2>]V,xӛIOƅ)Jͺ[)?cn28p#(mk+./phʮQ6?w7HIoSj)1<#-N9O1ͰސkIKr:(ŗ;rR&<93v@w(w:~:TFSޒ" ՊTdT9PIb3JzTQׄBP23ƵW*|@^)Qw?Iq =,<@ B8);50H-=T SA@@f5r[T%#c|Z&w(B)tDQ%vyC(,Ɵ|ʰi&<#u:3EHkzд)ndF>1V2kFGYL KMQlR&TB,igv8]C8Sf#ą4Q'?,= aV9WEXYrr*!cƯ~),=yџ]jlGeE̺5r_2Ԏ}d"a]0M9PZG17nE"Rr\YQ)!|5U(d=^ŗo8+2NU6jB[B5V.]ŲW/^䩬 ;Y"Vi$2ٲ_c(F^Egq{CP/ #K8Y+Q M1>ܞAߏ,gytޕn,zE$V.v.PyLapG9Tn:uiRZ! zI0?Џ1u#$6ɱGMhFdtd|~d\O9Ij**zD؍b)PBҽh-q ql%/{Gz*d7=QS]:RQbUMPᒯ$% du] XefQz$('ИZH#ARXDB ~`0.F|XXK)wFolzyhߚKz>.&n EjU,2' &iw[d[ V)*Qavl QDit[VIQhR@$)y~m|>?cJ+VH'6? 7 i.XH8Fި)dAYUBjE".4w-?l2Y.RjWD@Bج.߆s[H-gASF3Fj]آBP떬_>M%bt ?_rլ -h]r_ž[nȶQ+Gԭ_\Ê Z٦fet(|U('.g VFEN9}Ll4T&nto¨Ӓ X F "_fYzF~y& Gu]$O[v#].@$VA`ⱧTѰZ[2u+/mUC_ TnyѠ |l\ M"G[R$d|:ěFIire"ٵt,+ی1Z11udt*K2 sd; [)xW.z2jTh#DV\NO &e_vU2B^%0FH(/ԘI2>=L]dv UUpk"ijB$,O-0y<}~*T5LErE4B߳XXN:<9>Ed -V*uBLsN**JxRU辖,T( Gu @ůY{u|CJF(OLbnմiKhpFtx8#9FsFڋDTAn1veF^M ^kf.ĆݠVʓǰ3JaY@n&jLl:McӚ…vu?9w!/~#hM ڛ ̴nMA}m W,)(î.N y%$*={P9c DzH>Blu޾K78x->V,'JU \L]l>W*r-hXf~oI Z3f玱>vN3 uZTgg}Վ363:.g /-H+"PKۉSZ4Z_GlXMc7";ҿ (5fMUCOF6 CNft>$S1VaR&4) ٗay]%W A*|gX{Qc>iTX1F M`|![$P4ʊ$#,dɌ(?KTJR۸S%C7jHb浃j+N$,[.@˹_ ?.3ĵH"U$Z^ X02!Kc 8q.NMI6N&3n8exoWfPIJB<pREAdo$*m)e9D 5X[T$LΠ:]C$n#mC[P~Yt*d?\q^WXs!E-2#_mw8;2!vw:DUn$)GiGn3_o EZE3k-EHv.OûzE>"֛}l\/-nرQHԽab*#K׋eIƳd#G et\ ,:MێÜIC}m ٽO?eb%ːٰStB|Aznaz*FlQ/K uu*1wDvE֯SJTK;(4kƣ;v2P9`k{?~_[hʢ^9фǡ;m|]o9<#jz\wD,8V]]%K9er懇0n^FcI>`Ub+kօO1|NO]t+,Ȑl_ˮ6 ĒDbrz^pe7^[aþo確jN+xsNC߅wμ7|za2, omrbZ~,pN>;?Y,z[u◿jq 4aqڶNu6Zid@h!!F9#,#UrOa0=Då ,,,bE#ȮX3ªޏ=a< =&_~ ٵѽacj񫒆LsXuXB (wzEk_QIف*4'ѣSl{.,p۵2`jp^؇nZXPź^]wމ]aQ-oI5O3a] _wb ŭL]$"|sԩȬ= VсLIUbYY搮͢I$tf$2|r;~'GSXkᇦԭF4b4 xo[,04F~<}ۭR%myb׾\mlO.4}tE\7}M)tՉ13xF [-26t䢄&E"9;ٜrq e)K!:bwY }g;Jר)5D$!Kɤ9߫-K$$ hlDUFF J{s2R6rC&&0;@>]/Z3E,k;( 2^09 'index' return end oidreq = consumer.begin(identifier) rescue OpenID::OpenIDError => e flash[:error] = "Discovery failed for #{identifier}: #{e}" redirect_to :action => 'index' return end if params[:use_sreg] sregreq = OpenID::SReg::Request.new # required fields sregreq.request_fields(['email','nickname'], true) # optional fields sregreq.request_fields(['dob', 'fullname'], false) oidreq.add_extension(sregreq) oidreq.return_to_args['did_sreg'] = 'y' end if params[:use_pape] papereq = OpenID::PAPE::Request.new papereq.add_policy_uri(OpenID::PAPE::AUTH_PHISHING_RESISTANT) papereq.max_auth_age = 2*60*60 oidreq.add_extension(papereq) oidreq.return_to_args['did_pape'] = 'y' end if params[:force_post] oidreq.return_to_args['force_post']='x'*2048 end return_to = url_for :action => 'complete', :only_path => false realm = url_for :action => 'index', :id => nil, :only_path => false if oidreq.send_redirect?(realm, return_to, params[:immediate]) redirect_to oidreq.redirect_url(realm, return_to, params[:immediate]) else render :text => oidreq.html_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'}) end end def complete # FIXME - url_for some action is not necessarily the current URL. current_url = url_for(:action => 'complete', :only_path => false) parameters = params.reject{|k,v|request.path_parameters[k]} parameters.reject!{|k,v|%w{action controller}.include? k.to_s} oidresp = consumer.complete(parameters, current_url) case oidresp.status when OpenID::Consumer::FAILURE if oidresp.display_identifier flash[:error] = ("Verification of #{oidresp.display_identifier}"\ " failed: #{oidresp.message}") else flash[:error] = "Verification failed: #{oidresp.message}" end when OpenID::Consumer::SUCCESS flash[:success] = ("Verification of #{oidresp.display_identifier}"\ " succeeded.") if params[:did_sreg] sreg_resp = OpenID::SReg::Response.from_success_response(oidresp) sreg_message = "Simple Registration data was requested" if sreg_resp.empty? sreg_message << ", but none was returned." else sreg_message << ". The following data were sent:" sreg_resp.data.each {|k,v| sreg_message << "
#{k}: #{v}" } end flash[:sreg_results] = sreg_message end if params[:did_pape] pape_resp = OpenID::PAPE::Response.from_success_response(oidresp) pape_message = "A phishing resistant authentication method was requested" if pape_resp.auth_policies.member? OpenID::PAPE::AUTH_PHISHING_RESISTANT pape_message << ", and the server reported one." else pape_message << ", but the server did not report one." end if pape_resp.auth_time pape_message << "
Authentication time: #{pape_resp.auth_time} seconds" end if pape_resp.nist_auth_level pape_message << "
NIST Auth Level: #{pape_resp.nist_auth_level}" end flash[:pape_results] = pape_message end when OpenID::Consumer::SETUP_NEEDED flash[:alert] = "Immediate request failed - Setup Needed" when OpenID::Consumer::CANCEL flash[:alert] = "OpenID transaction cancelled." else end redirect_to :action => 'index' end private def consumer if @consumer.nil? dir = Pathname.new(RAILS_ROOT).join('db').join('cstore') store = OpenID::Store::Filesystem.new(dir) @consumer = OpenID::Consumer.new(session, store) end return @consumer end end ruby-openid-2.7.0debian.orig/examples/rails_openid/app/controllers/server_controller.rb0000644000175000017500000001467212512544714031040 0ustar sbadiasbadiarequire 'pathname' require "openid" require "openid/consumer/discovery" require 'openid/extensions/sreg' require 'openid/extensions/pape' require 'openid/store/filesystem' class ServerController < ApplicationController include ServerHelper include OpenID::Server layout nil def index begin oidreq = server.decode_request(params) rescue ProtocolError => e # invalid openid request, so just display a page with an error message render :text => e.to_s, :status => 500 return end # no openid.mode was given unless oidreq render :text => "This is an OpenID server endpoint." return end oidresp = nil if oidreq.kind_of?(CheckIDRequest) identity = oidreq.identity if oidreq.id_select if oidreq.immediate oidresp = oidreq.answer(false) elsif session[:username].nil? # The user hasn't logged in. show_decision_page(oidreq) return else # Else, set the identity to the one the user is using. identity = url_for_user end end if oidresp nil elsif self.is_authorized(identity, oidreq.trust_root) oidresp = oidreq.answer(true, nil, identity) # add the sreg response if requested add_sreg(oidreq, oidresp) # ditto pape add_pape(oidreq, oidresp) elsif oidreq.immediate server_url = url_for :action => 'index' oidresp = oidreq.answer(false, server_url) else show_decision_page(oidreq) return end else oidresp = server.handle_request(oidreq) end self.render_response(oidresp) end def show_decision_page(oidreq, message="Do you trust this site with your identity?") session[:last_oidreq] = oidreq @oidreq = oidreq if message flash[:notice] = message end render :template => 'server/decide', :layout => 'server' end def user_page # Yadis content-negotiation: we want to return the xrds if asked for. accept = request.env['HTTP_ACCEPT'] # This is not technically correct, and should eventually be updated # to do real Accept header parsing and logic. Though I expect it will work # 99% of the time. if accept and accept.include?('application/xrds+xml') user_xrds return end # content negotiation failed, so just render the user page xrds_url = url_for(:controller=>'user',:action=>params[:username])+'/xrds' identity_page = <

OpenID identity page for #{params[:username]}

EOS # Also add the Yadis location header, so that they don't have # to parse the html unless absolutely necessary. response.headers['X-XRDS-Location'] = xrds_url render :text => identity_page end def user_xrds types = [ OpenID::OPENID_2_0_TYPE, OpenID::OPENID_1_0_TYPE, OpenID::SREG_URI, ] render_xrds(types) end def idp_xrds types = [ OpenID::OPENID_IDP_2_0_TYPE, ] render_xrds(types) end def decision oidreq = session[:last_oidreq] session[:last_oidreq] = nil if params[:yes].nil? redirect_to oidreq.cancel_url return else id_to_send = params[:id_to_send] identity = oidreq.identity if oidreq.id_select if id_to_send and id_to_send != "" session[:username] = id_to_send session[:approvals] = [] identity = url_for_user else msg = "You must enter a username to in order to send " + "an identifier to the Relying Party." show_decision_page(oidreq, msg) return end end if session[:approvals] session[:approvals] << oidreq.trust_root else session[:approvals] = [oidreq.trust_root] end oidresp = oidreq.answer(true, nil, identity) add_sreg(oidreq, oidresp) add_pape(oidreq, oidresp) return self.render_response(oidresp) end end protected def server if @server.nil? server_url = url_for :action => 'index', :only_path => false dir = Pathname.new(RAILS_ROOT).join('db').join('openid-store') store = OpenID::Store::Filesystem.new(dir) @server = Server.new(store, server_url) end return @server end def approved(trust_root) return false if session[:approvals].nil? return session[:approvals].member?(trust_root) end def is_authorized(identity_url, trust_root) return (session[:username] and (identity_url == url_for_user) and self.approved(trust_root)) end def render_xrds(types) type_str = "" types.each { |uri| type_str += "#{uri}\n " } yadis = < #{type_str} #{url_for(:controller => 'server', :only_path => false)} EOS render :text => yadis, :content_type => 'application/xrds+xml' end def add_sreg(oidreq, oidresp) # check for Simple Registration arguments and respond sregreq = OpenID::SReg::Request.from_openid_request(oidreq) return if sregreq.nil? # In a real application, this data would be user-specific, # and the user should be asked for permission to release # it. sreg_data = { 'nickname' => session[:username], 'fullname' => 'Mayor McCheese', 'email' => 'mayor@example.com' } sregresp = OpenID::SReg::Response.extract_response(sregreq, sreg_data) oidresp.add_extension(sregresp) end def add_pape(oidreq, oidresp) papereq = OpenID::PAPE::Request.from_openid_request(oidreq) return if papereq.nil? paperesp = OpenID::PAPE::Response.new paperesp.nist_auth_level = 0 # we don't even do auth at all! oidresp.add_extension(paperesp) end def render_response(oidresp) if oidresp.needs_signing signed_response = server.signatory.sign(oidresp) end web_response = server.encode_response(oidresp) case web_response.code when HTTP_OK render :text => web_response.body, :status => 200 when HTTP_REDIRECT redirect_to web_response.headers['location'] else render :text => web_response.body, :status => 400 end end end ruby-openid-2.7.0debian.orig/examples/rails_openid/app/controllers/login_controller.rb0000644000175000017500000000234012512544714030627 0ustar sbadiasbadia# Controller for handling the login, logout process for "users" of our # little server. Users have no password. This is just an example. require 'openid' class LoginController < ApplicationController layout 'server' def base_url url_for(:controller => 'login', :action => nil, :only_path => false) end def index response.headers['X-XRDS-Location'] = url_for(:controller => "server", :action => "idp_xrds", :only_path => false) @base_url = base_url # just show the login page end def submit user = params[:username] # if we get a user, log them in by putting their username in # the session hash. unless user.nil? session[:username] = user unless user.nil? session[:approvals] = [] flash[:notice] = "Your OpenID URL is #{base_url}user/#{user}

Proceed to step 2 below." else flash[:error] = "Sorry, couldn't log you in. Try again." end redirect_to :action => 'index' end def logout # delete the username from the session hash session[:username] = nil session[:approvals] = nil redirect_to :action => 'index' end end ruby-openid-2.7.0debian.orig/examples/rails_openid/Gemfile0000644000175000017500000000143612512544714023101 0ustar sbadiasbadiasource 'https://rubygems.org' gem 'rails', '3.2.13' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' gem 'sqlite3' gem 'json' # Gems used only for assets and not required # in production environments by default. group :assets do gem 'sass-rails', '~> 3.2.3' gem 'coffee-rails', '~> 3.2.1' # See https://github.com/sstephenson/execjs#readme for more supported runtimes # gem 'therubyracer', :platforms => :ruby gem 'uglifier', '>= 1.0.3' end gem 'jquery-rails' # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' # To use Jbuilder templates for JSON # gem 'jbuilder' # Use unicorn as the app server # gem 'unicorn' # Deploy with Capistrano # gem 'capistrano' # To use debugger # gem 'ruby-debug' gem 'ruby-openid' ruby-openid-2.7.0debian.orig/examples/rails_openid/log/0000755000175000017500000000000012512544714022363 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/log/development.log0000644000175000017500000054477612512544714025437 0ustar sbadiasbadiaConnecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:22:11 -0700 2013 ActionController::RoutingError (No route matches [GET] "/consumer"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (3.3ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:23:00 -0700 2013 LoadError (no such file to load -- openid): app/controllers/consumer_controller.rb:3 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (13.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (31.1ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:23:40 -0700 2013 Processing by ConsumerController#index as HTML Completed 500 Internal Server Error in 24ms ActionView::MissingTemplate (Missing template consumer/index, application/index with {:handlers=>[:coffee, :erb, :builder], :locale=>[:en], :formats=>[:html]}. Searched in: * "/Users/marcel/.gem/ruby/1.8/gems/ruby-openid-2.2.3/examples/rails_openid/app/views" ): actionpack (3.2.13) lib/action_view/path_set.rb:58:in `find' actionpack (3.2.13) lib/action_view/lookup_context.rb:109:in `find_template' actionpack (3.2.13) lib/action_view/renderer/abstract_renderer.rb:3:in `__send__' actionpack (3.2.13) lib/action_view/renderer/abstract_renderer.rb:3:in `find_template' actionpack (3.2.13) lib/action_view/renderer/template_renderer.rb:34:in `determine_template' actionpack (3.2.13) lib/action_view/renderer/template_renderer.rb:10:in `render' actionpack (3.2.13) lib/action_view/renderer/renderer.rb:36:in `render_template' actionpack (3.2.13) lib/action_view/renderer/renderer.rb:17:in `render' actionpack (3.2.13) lib/abstract_controller/rendering.rb:110:in `_render_template' actionpack (3.2.13) lib/action_controller/metal/streaming.rb:225:in `_render_template' actionpack (3.2.13) lib/abstract_controller/rendering.rb:103:in `render_to_body' actionpack (3.2.13) lib/action_controller/metal/renderers.rb:28:in `render_to_body' actionpack (3.2.13) lib/action_controller/metal/compatibility.rb:50:in `render_to_body' actionpack (3.2.13) lib/abstract_controller/rendering.rb:88:in `render' actionpack (3.2.13) lib/action_controller/metal/rendering.rb:16:in `render' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:40:in `render' activesupport (3.2.13) lib/active_support/core_ext/benchmark.rb:5:in `ms' /opt/local/lib/ruby/1.8/benchmark.rb:308:in `realtime' activesupport (3.2.13) lib/active_support/core_ext/benchmark.rb:5:in `ms' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:40:in `render' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:83:in `cleanup_view_runtime' activerecord (3.2.13) lib/active_record/railties/controller_runtime.rb:24:in `cleanup_view_runtime' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:39:in `render' actionpack (3.2.13) lib/action_controller/metal/implicit_render.rb:10:in `default_render' actionpack (3.2.13) lib/action_controller/metal/implicit_render.rb:5:in `send_action' actionpack (3.2.13) lib/abstract_controller/base.rb:167:in `process_action' actionpack (3.2.13) lib/action_controller/metal/rendering.rb:10:in `process_action' actionpack (3.2.13) lib/abstract_controller/callbacks.rb:18:in `process_action' activesupport (3.2.13) lib/active_support/callbacks.rb:414:in `_run__1789127949__process_action__199225275__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_process_action_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/abstract_controller/callbacks.rb:17:in `process_action' actionpack (3.2.13) lib/action_controller/metal/rescue.rb:29:in `process_action' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:30:in `process_action' activesupport (3.2.13) lib/active_support/notifications.rb:123:in `instrument' activesupport (3.2.13) lib/active_support/notifications/instrumenter.rb:20:in `instrument' activesupport (3.2.13) lib/active_support/notifications.rb:123:in `instrument' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:29:in `process_action' actionpack (3.2.13) lib/action_controller/metal/params_wrapper.rb:207:in `process_action' activerecord (3.2.13) lib/active_record/railties/controller_runtime.rb:18:in `process_action' actionpack (3.2.13) lib/abstract_controller/base.rb:121:in `process' actionpack (3.2.13) lib/abstract_controller/rendering.rb:45:in `process' actionpack (3.2.13) lib/action_controller/metal.rb:203:in `dispatch' actionpack (3.2.13) lib/action_controller/metal/rack_delegation.rb:14:in `dispatch' actionpack (3.2.13) lib/action_controller/metal.rb:246:in `action' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:73:in `call' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:73:in `dispatch' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:36:in `call' journey (1.0.4) lib/journey/router.rb:68:in `call' journey (1.0.4) lib/journey/router.rb:56:in `each' journey (1.0.4) lib/journey/router.rb:56:in `call' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:612:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call' rack (1.4.5) lib/rack/etag.rb:23:in `call' rack (1.4.5) lib/rack/conditionalget.rb:25:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/head.rb:14:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/params_parser.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:242:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/missing_template.erb within rescues/layout (1.9ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:25:07 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (6.1ms) Compiled application.css (1ms) (pid 67167) Compiled jquery.js (13ms) (pid 67167) Compiled jquery_ujs.js (1ms) (pid 67167) Compiled application.js (113ms) (pid 67167) Completed 200 OK in 426ms (Views: 425.4ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /application.css - 200 OK (4ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /jquery.js - 200 OK (15ms) Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /jquery_ujs.js - 200 OK (13ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /application.js - 200 OK (32ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:25:22 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Completed 500 Internal Server Error in 2ms NameError (uninitialized constant ConsumerController::RAILS_ROOT): app/controllers/consumer_controller.rb:116:in `consumer' app/controllers/consumer_controller.rb:23:in `start' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (121.5ms) Connecting to database specified by database.yml Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:26:13 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3009/open_id/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 661ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582b69%7D%7BodxU%2BQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.invalidate_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fserver&openid.response_nonce=2013-03-31T12%3A26%3A17ZVVzuGN&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=HHdHfhXu%2FmKVDXkCffxuD%2BYuNeU%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cinvalidate_handle%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"HHdHfhXu/mKVDXkCffxuD+YuNeU=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/open_id/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T12:26:17ZVVzuGN", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/open_id/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,invalidate_handle,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.invalidate_handle"=>"{HMAC-SHA1}{51582b66}{vdrbdQ==}", "openid.assoc_handle"=>"{HMAC-SHA1}{51582b69}{odxU+Q==}", "openid.claimed_id"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3010/consumer Completed 302 Found in 4ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (14.7ms) Completed 200 OK in 59ms (Views: 58.8ms | ActiveRecord: 0.0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Served asset /application.js - 304 Not Modified (8ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Served asset /application.css - 304 Not Modified (132ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:30:38 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (4.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (23.6ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:30:45 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (18.9ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:31:30 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (7.0ms) Completed 200 OK in 198ms (Views: 197.4ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:31 -0700 2013 Served asset /jquery.js - 304 Not Modified (7ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:31:31 -0700 2013 Served asset /application.css - 304 Not Modified (3ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:31 -0700 2013 Served asset /application.js - 304 Not Modified (44ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:31:36 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3009/open_id/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 65ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582cb5%7D%7B2olQew%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.invalidate_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fserver&openid.response_nonce=2013-03-31T12%3A31%3A49Z8CDJUo&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=skvSU5yuQsW%2BZwCkDbUbGmtMngc%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cinvalidate_handle%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"skvSU5yuQsW+ZwCkDbUbGmtMngc=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/open_id/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T12:31:49Z8CDJUo", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/open_id/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,invalidate_handle,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.invalidate_handle"=>"{HMAC-SHA1}{51582b66}{vdrbdQ==}", "openid.assoc_handle"=>"{HMAC-SHA1}{51582cb5}{2olQew==}", "openid.claimed_id"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3010/consumer Completed 302 Found in 65ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.7ms) Completed 200 OK in 7ms (Views: 6.9ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Connecting to database specified by database.yml Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:32:59 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.0ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (19.9ms) Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:33:19 -0700 2013 Processing by ServerController#index as HTML Rendered text template (0.0ms) Completed 500 Internal Server Error in 31ms (Views: 25.3ms | ActiveRecord: 0.0ms) Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:33:41 -0700 2013 Processing by ServerController#index as HTML Rendered text template (0.0ms) Completed 500 Internal Server Error in 5ms (Views: 2.7ms | ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 11ms (Views: 10.3ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Started GET "/open_id/marcel" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 ActionController::RoutingError (No route matches [GET] "/open_id/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 38ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.7ms) Completed 200 OK in 8ms (Views: 8.0ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver" for 127.0.0.1 at Sun Mar 31 05:34:12 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server"} Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:34:12 -0700 2013 Processing by ServerController#index as application/xrds+xml Rendered text template (0.0ms) Completed 500 Internal Server Error in 5ms (Views: 1.9ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 20ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.6ms) Completed 200 OK in 11ms (Views: 10.2ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 05:35:31 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 05:35:31 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 3ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started POST "/server" for 127.0.0.1 at Sun Mar 31 05:35:32 -0700 2013 Processing by ServerController#index as */* Parameters: {"openid.mode"=>"associate", "openid.assoc_type"=>"HMAC-SHA1", "openid.session_type"=>"DH-SHA1", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.dh_consumer_public"=>"Ohd6vp/95+pq56SpKTaquSLrgWcVYQwVDbe+KsVnfn/bWAsT2TGS3v7AjwWKx5rfCZauIQ/c55uwMjT5iX5sAQFcNdOVtl5Ue42oFfkHDu01A7xovf2ZUdbw10m0Cl+g0BjDZRBagDShrlvBP3SZDMPvQu4o/04GhA6rChWnaGA="} WARNING: Can't verify CSRF token authenticity Rendered text template (0.0ms) Completed 200 OK in 40ms (Views: 0.7ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 308ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:35:32 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendered server/decide.html.erb within layouts/server (1.2ms) Completed 200 OK in 21ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:37:07 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendered server/decide.html.erb within layouts/server (2.1ms) Completed 200 OK in 18ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:37:10 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendered server/decide.html.erb within layouts/server (1.1ms) Completed 200 OK in 16ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:38:02 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.0ms) Completed 200 OK in 15ms (Views: 8.3ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:38:11 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.2ms) Completed 200 OK in 18ms (Views: 14.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:39:23 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.1ms) Completed 200 OK in 8ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:39:26 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 11ms (Views: 4.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:39:52 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Completed 500 Internal Server Error in 1ms NoMethodError (undefined method `identity' for nil:NilClass): app/controllers/server_controller.rb:143:in `decision' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.7ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.4ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (15.5ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:41:02 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Completed 500 Internal Server Error in 1ms NoMethodError (undefined method `identity' for nil:NilClass): app/controllers/server_controller.rb:143:in `decision' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.2ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (14.4ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:41:56 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.3ms | ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:42:11 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 12ms (Views: 10.9ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:42:12 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:42:12 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:42:12 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 05:42:28 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 05:42:28 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 31ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:42:28 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 8ms (Views: 3.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:42:36 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:45:38 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 19ms (Views: 10.1ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:46:02 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 7ms (Views: 3.7ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:46:33 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.5ms) session: Rendering decide template! Completed 500 Internal Server Error in 10ms AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".): app/controllers/server_controller.rb:88:in `show_decision_page' app/controllers/server_controller.rb:45:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (2.2ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (5.0ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (25.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:46:47 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session: Completed 200 OK in 8ms (Views: 4.8ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:48:24 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.3ms) session: Completed 200 OK in 15ms (Views: 11.0ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:48:44 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:54:41 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.6ms) session: session size: 804 Completed 200 OK in 14ms (Views: 5.4ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:54:59 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session: Completed 500 Internal Server Error in 12ms TypeError (can't dump anonymous module #): app/controllers/server_controller.rb:45:in `dump' app/controllers/server_controller.rb:45:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (27.3ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:56:19 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 Completed 200 OK in 8ms (Views: 4.3ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:56:21 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:56:26 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:56:36 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 Completed 200 OK in 8ms (Views: 3.7ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:56:37 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.5ms) session last_oidreq: session last_oidreq size: 804 Completed 200 OK in 7ms (Views: 3.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:56:44 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:57:14 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:57:35 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 3ms (Views: 2.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:58:17 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.3ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:59:23 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: 0df6cf9c44f69c6a4ab15e8a889cdbfc Completed 200 OK in 8ms (Views: 3.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:00:27 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: 0df6cf9c44f69c6a4ab15e8a889cdbfc session_id cookie: Completed 200 OK in 8ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:00:46 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.9ms) session last_oidreq: session last_oidreq size: 804 session_id: 0df6cf9c44f69c6a4ab15e8a889cdbfc session_id cookie: BAh7CSIPc2Vzc2lvbl9pZCIlMGRmNmNmOWM0NGY2OWM2YTRhYjE1ZThhODg5Y2RiZmMiCmhlbGxvIgp3b3JsZCIKZmxhc2hvOiVBY3Rpb25EaXNwYXRjaDo6Rmxhc2g6OkZsYXNoSGFzaAk6DUBmbGFzaGVzewY6C25vdGljZSIvRG8geW91IHRydXN0IHRoaXMgc2l0ZSB3aXRoIHlvdXIgaWRlbnRpdHk/OgpAdXNlZG86CFNldAY6CkBoYXNoewA6DEBjbG9zZWRGOglAbm93MCIQbGFzdF9vaWRyZXFvOiNPcGVuSUQ6OlNlcnZlcjo6Q2hlY2tJRFJlcXVlc3QOOhBAdHJ1c3Rfcm9vdCIjaHR0cDovL2xvY2FsaG9zdDozMDEwL2NvbnN1bWVyOg9AcmV0dXJuX3RvIixodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXIvY29tcGxldGU6DUBtZXNzYWdlbzoUT3BlbklEOjpNZXNzYWdlCDoQQG5hbWVzcGFjZXNvOhlPcGVuSUQ6Ok5hbWVzcGFjZU1hcAg6GEBhbGlhc190b19uYW1lc3BhY2V7BjoTbnVsbF9uYW1lc3BhY2UiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOhlAaW1wbGljaXRfbmFtZXNwYWNlc1sAOhhAbmFtZXNwYWNlX3RvX2FsaWFzewYiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOxU6E0BvcGVuaWRfbnNfdXJpQBc6CkBhcmdzew1bB0AXIgltb2RlIhJjaGVja2lkX3NldHVwWwdAFyIPY2xhaW1lZF9pZCI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3RbBzoTYmFyZV9uYW1lc3BhY2UiC2FjdGlvbiIKaW5kZXhbBzsaIg9jb250cm9sbGVyIgtzZXJ2ZXJbB0AXIhFhc3NvY19oYW5kbGUiJHtITUFDLVNIQTF9ezUxNTgyZDk0fXtjZGtvMWc9PX1bB0AXIg5yZXR1cm5fdG9AE1sHQBciCnJlYWxtQBJbB0AXIg1pZGVudGl0eSI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3Q6D0BpbW1lZGlhdGVGOg5AaWRlbnRpdHlAMToSQGFzc29jX2hhbmRsZUAqOhBAY2xhaW1lZF9pZEAhOgpAbW9kZSISY2hlY2tpZF9zZXR1cDoRQG9wX2VuZHBvaW50IiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVy--e9977c9d345b7da60a35bbd6b27618a288f54057 Completed 200 OK in 31ms (Views: 14.7ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:01:27 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CSIPc2Vzc2lvbl9pZCIlMGRmNmNmOWM0NGY2OWM2YTRhYjE1ZThhODg5Y2RiZmMiCmhlbGxvIgp3b3JsZCIQbGFzdF9vaWRyZXFvOiNPcGVuSUQ6OlNlcnZlcjo6Q2hlY2tJRFJlcXVlc3QOOhBAdHJ1c3Rfcm9vdCIjaHR0cDovL2xvY2FsaG9zdDozMDEwL2NvbnN1bWVyOg9AcmV0dXJuX3RvIixodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXIvY29tcGxldGU6DUBtZXNzYWdlbzoUT3BlbklEOjpNZXNzYWdlCDoQQG5hbWVzcGFjZXNvOhlPcGVuSUQ6Ok5hbWVzcGFjZU1hcAg6GEBhbGlhc190b19uYW1lc3BhY2V7BjoTbnVsbF9uYW1lc3BhY2UiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOhlAaW1wbGljaXRfbmFtZXNwYWNlc1sAOhhAbmFtZXNwYWNlX3RvX2FsaWFzewYiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOw06E0BvcGVuaWRfbnNfdXJpQBE6CkBhcmdzew1bB0ARIgltb2RlIhJjaGVja2lkX3NldHVwWwdAESIPY2xhaW1lZF9pZCI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3RbBzoTYmFyZV9uYW1lc3BhY2UiC2FjdGlvbiIKaW5kZXhbBzsSIg9jb250cm9sbGVyIgtzZXJ2ZXJbB0ARIhFhc3NvY19oYW5kbGUiJHtITUFDLVNIQTF9ezUxNTgyZDk0fXtjZGtvMWc9PX1bB0ARIg5yZXR1cm5fdG9ADVsHQBEiCnJlYWxtQAxbB0ARIg1pZGVudGl0eSI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3Q6D0BpbW1lZGlhdGVGOg5AaWRlbnRpdHlAKzoSQGFzc29jX2hhbmRsZUAkOhBAY2xhaW1lZF9pZEAbOgpAbW9kZSISY2hlY2tpZF9zZXR1cDoRQG9wX2VuZHBvaW50IiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cw--097664684a5b4ec726b2e9621c60066bdffa2b08 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:01:46 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiViMjkzOWYzZGM1MGUzZGVhN2MzMjQwODgwMzk4ZDRlZg==--5c9b11469badcabaca82548d4d506f6b7b1e834f hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:07:21 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.2ms) session last_oidreq: session last_oidreq size: 804 session_id: d50d3dd624bc8ca8e44f1203c96a8f93 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiVkNTBkM2RkNjI0YmM4Y2E4ZTQ0ZjEyMDNjOTZhOGY5Mw==--4184fd96c6f41491285b5f6c1e96b4b72e28c2f8 Completed 200 OK in 10ms (Views: 4.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:07:33 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (157.0ms) Completed 500 Internal Server Error in 166ms ActionView::Template::Error (undefined local variable or method `form_authenticity_token_field' for #<#:0x10358a698>): 1:
2: <%= form_authenticity_token_field %> 3: 4: 5: app/views/server/decide.html.erb:2:in `_app_views_server_decide_html_erb___1096845836_2175551400' app/controllers/server_controller.rb:92:in `show_decision_page' app/controllers/server_controller.rb:43:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.3ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (15.6ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:09:13 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (42.6ms) Completed 500 Internal Server Error in 49ms ActionView::Template::Error (undefined local variable or method `form_authenticity_param' for #<#:0x103920618>): 1: 2: 3: 4:
Site:<%= @oidreq.trust_root %>
5: app/views/server/decide.html.erb:2:in `_app_views_server_decide_html_erb___1096845836_2177422820' app/controllers/server_controller.rb:92:in `show_decision_page' app/controllers/server_controller.rb:43:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (3.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (20.9ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:10:58 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.0ms) session last_oidreq: session last_oidreq size: 804 session_id: d50d3dd624bc8ca8e44f1203c96a8f93 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMTVIMWQ0bEVzMnA4Qjd0enZHTXNIZXRLOUtPcTZCbFl4UFN6dyt2SFJTckE9Ig9zZXNzaW9uX2lkIiVkNTBkM2RkNjI0YmM4Y2E4ZTQ0ZjEyMDNjOTZhOGY5MyIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--0b12a84d3b56c065d035566362e3e9374de86039 Completed 200 OK in 8ms (Views: 4.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:00 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMTVIMWQ0bEVzMnA4Qjd0enZHTXNIZXRLOUtPcTZCbFl4UFN6dyt2SFJTckE9Ig9zZXNzaW9uX2lkIiVkNTBkM2RkNjI0YmM4Y2E4ZTQ0ZjEyMDNjOTZhOGY5MyIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToTQG9wZW5pZF9uc191cmlAGToKQGFyZ3N7DVsHQBkiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0AZIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxoiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBkiDnJldHVybl90b0AVWwdAGSIKcmVhbG1AFFsHQBkiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAzOhJAYXNzb2NfaGFuZGxlQCw6EEBjbGFpbWVkX2lkQCM6CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI=--efe18d78f0dd5ccfbb16f8706b35781d95ffead8 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:11:03 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: b0111bc499a041f6669c0cffd50c4854 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiViMDExMWJjNDk5YTA0MWY2NjY5YzBjZmZkNTBjNDg1NA==--73c5bfc2bb790437f2b141aaf0c20cd6cc426da7 Completed 200 OK in 9ms (Views: 3.5ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:11:05 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.8ms) session last_oidreq: session last_oidreq size: 804 session_id: b0111bc499a041f6669c0cffd50c4854 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMURlelQzMjdHQk9aRUdxakRaM2pjeTFjY3ZsRmN0eHJQdUF2UGJLWUg3WTA9Ig9zZXNzaW9uX2lkIiViMDExMWJjNDk5YTA0MWY2NjY5YzBjZmZkNTBjNDg1NCIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--4aa0ecdd65e5219704711e40c58139be1348db1f Completed 200 OK in 10ms (Views: 5.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:06 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMURlelQzMjdHQk9aRUdxakRaM2pjeTFjY3ZsRmN0eHJQdUF2UGJLWUg3WTA9Ig9zZXNzaW9uX2lkIiViMDExMWJjNDk5YTA0MWY2NjY5YzBjZmZkNTBjNDg1NCIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToTQG9wZW5pZF9uc191cmlAGToKQGFyZ3N7DVsHQBkiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0AZIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxoiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBkiDnJldHVybl90b0AVWwdAGSIKcmVhbG1AFFsHQBkiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAzOhJAYXNzb2NfaGFuZGxlQCw6EEBjbGFpbWVkX2lkQCM6CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI=--2e2b7c25a4b12809bc26063679446f2ea9bb0c95 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:40 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiVkZTEzMjgwMDA5ZGU5NGQ1NjkzYWExNjUxNDFmMWYyNQ==--fb03aa366527aebbe8dd7fd9a6be3905ea7690b6 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 4ms (Views: 1.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:11:42 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: 396fcb58d8777c7f869bf8084e96482c session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiUzOTZmY2I1OGQ4Nzc3YzdmODY5YmY4MDg0ZTk2NDgyYw==--48268edfcda33e221ff56a92f7c2cc30efd4951a Completed 200 OK in 14ms (Views: 5.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:43 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMVBONjA1NXlibkNzaWJEZ1pTZ0k5KzEwZStoVXdRZUpPYU5FYzRlL3J0MW89Ig9zZXNzaW9uX2lkIiUzOTZmY2I1OGQ4Nzc3YzdmODY5YmY4MDg0ZTk2NDgyYyIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--9d8e44ba14ab5c85a086e860ea1481f71067e88f hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:12:51 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.0ms) session last_oidreq: session last_oidreq size: 804 session_id: 2c66ed926ccfe2103c298469eb4818f8 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiUyYzY2ZWQ5MjZjY2ZlMjEwM2MyOTg0NjllYjQ4MThmOA==--6457aa16715de946fb9167e165af7f022d49cd5f Completed 200 OK in 7ms (Views: 3.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:12:53 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"_token"=>"rLGwlRuk0Zz/nS165br3PrN5Zre3xpwKpSsHGDqntog=", "yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMXJMR3dsUnVrMFp6L25TMTY1YnIzUHJONVpyZTN4cHdLcFNzSEdEcW50b2c9Ig9zZXNzaW9uX2lkIiUyYzY2ZWQ5MjZjY2ZlMjEwM2MyOTg0NjllYjQ4MThmOCIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--f8ed02db84ccf0f80fc1bd2f0f4095cbc249caac hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.9ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:15:54 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.7ms) session last_oidreq: session last_oidreq size: 804 session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMQ==--0b1f7487ae5567045e91d39d107132c75a1e1c59 Completed 200 OK in 45ms (Views: 40.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:15:55 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--9a1ec542115a344418fdc5587685b73737444aef hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.7ms) Completed 200 OK in 5ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:15:58 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIlZZb3UgbXVzdCBlbnRlciBhIHVzZXJuYW1lIHRvIGluIG9yZGVyIHRvIHNlbmQgYW4gaWRlbnRpZmllciB0byB0aGUgUmVseWluZyBQYXJ0eS46CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToKQGFyZ3N7DVsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHQBkiD2NsYWltZWRfaWQiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIJbW9kZSISY2hlY2tpZF9zZXR1cFsHOxkiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiDnJldHVybl90b0AVWwdAGSIRYXNzb2NfaGFuZGxlIiR7SE1BQy1TSEExfXs1MTU4MmQ5NH17Y2RrbzFnPT19WwdAGSINaWRlbnRpdHkiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIKcmVhbG1AFDoTQG9wZW5pZF9uc191cmlAGToPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAxOhJAYXNzb2NfaGFuZGxlQC46EUBvcF9lbmRwb2ludCIhaHR0cDovL2xvY2FsaG9zdDozMDA5L3NlcnZlcjoKQG1vZGUiEmNoZWNraWRfc2V0dXA6EEBjbGFpbWVkX2lkQCM=--d18faa6ccd17ce34ee9d7d0cc67cfa3b8e5589c1 hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.8ms) Completed 200 OK in 6ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:23 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiVllvdSBtdXN0IGVudGVyIGEgdXNlcm5hbWUgdG8gaW4gb3JkZXIgdG8gc2VuZCBhbiBpZGVudGlmaWVyIHRvIHRoZSBSZWx5aW5nIFBhcnR5LjoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--755060a8760641df75a8c6ce57f0e8e076a90b57 hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 7ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:27 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIlZZb3UgbXVzdCBlbnRlciBhIHVzZXJuYW1lIHRvIGluIG9yZGVyIHRvIHNlbmQgYW4gaWRlbnRpZmllciB0byB0aGUgUmVseWluZyBQYXJ0eS46CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToKQGFyZ3N7DVsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHQBkiD2NsYWltZWRfaWQiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIJbW9kZSISY2hlY2tpZF9zZXR1cFsHOxkiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiDnJldHVybl90b0AVWwdAGSIRYXNzb2NfaGFuZGxlIiR7SE1BQy1TSEExfXs1MTU4MmQ5NH17Y2RrbzFnPT19WwdAGSINaWRlbnRpdHkiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIKcmVhbG1AFDoTQG9wZW5pZF9uc191cmlAGToPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAxOhJAYXNzb2NfaGFuZGxlQC46EUBvcF9lbmRwb2ludCIhaHR0cDovL2xvY2FsaG9zdDozMDA5L3NlcnZlcjoKQG1vZGUiEmNoZWNraWRfc2V0dXA6EEBjbGFpbWVkX2lkQCM=--d18faa6ccd17ce34ee9d7d0cc67cfa3b8e5589c1 hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 4ms (Views: 3.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiVllvdSBtdXN0IGVudGVyIGEgdXNlcm5hbWUgdG8gaW4gb3JkZXIgdG8gc2VuZCBhbiBpZGVudGlmaWVyIHRvIHRoZSBSZWx5aW5nIFBhcnR5LjoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--755060a8760641df75a8c6ce57f0e8e076a90b57 hello: world last_oidreq: Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A16%3A32ZBnQWSS&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=nk5Cd60iCeaC5tEfTFXeq8bJxkM%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 50ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A16%3A32ZBnQWSS&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=nk5Cd60iCeaC5tEfTFXeq8bJxkM%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"nk5Cd60iCeaC5tEfTFXeq8bJxkM=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:16:32ZBnQWSS", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 103ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (1.3ms) Completed 200 OK in 229ms (Views: 219.6ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:53 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>"marcel"} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CyIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSINdXNlcm5hbWUiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9tYXJjZWwiCmhlbGxvIgp3b3JsZCIKZmxhc2hvOiVBY3Rpb25EaXNwYXRjaDo6Rmxhc2g6OkZsYXNoSGFzaAk6DUBmbGFzaGVzewY6CmVycm9yIgGaVmVyaWZpY2F0aW9uIGZhaWxlZDogSFRUUCBSZXNwb25zZSBzdGF0dXMgZnJvbSBpZGVudGl0eSBVUkwgaG9zdCBpcyBub3QgIjIwMCIuR290IHN0YXR1cyAiNDA0IiBmb3IgaHR0cDovL2xvY2FsaG9zdDozMDA5L3VzZXIvaHR0cDovL2xvY2FsaG9zdDozMDA5L21hcmNlbDoKQHVzZWRvOghTZXQGOgpAaGFzaHsGOwdUOgxAY2xvc2VkRjoJQG5vdzAiDmFwcHJvdmFsc1sGIiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI=--419dee51ac0f7222ab6c721397583a987665e92b hello: world last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:57 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig11c2VybmFtZSIhaHR0cDovL2xvY2FsaG9zdDozMDA5L21hcmNlbCIPc2Vzc2lvbl9pZCIlZmY0YWIzYzI4MzNkNjMyNGYxZmNjM2E0ZGU1ODdmZTEiCmhlbGxvIgp3b3JsZCIOYXBwcm92YWxzWwYiI2h0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lcg==--793b2103b83a8f1f36926f105f4f81683d9f5a7f hello: world last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:17:08 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A08ZUxQiz5&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=4HAQxaR%2B5Mujm5aHJjPjV8E6kPo%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 196ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A08ZUxQiz5&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=4HAQxaR%2B5Mujm5aHJjPjV8E6kPo%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"4HAQxaR+5Mujm5aHJjPjV8E6kPo=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:17:08ZUxQiz5", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (3.2ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 70ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (1.1ms) Completed 200 OK in 21ms (Views: 17.4ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A16ZE1EQft&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=EBYQ%2BmvGOdl6C1fW2uvPjRS3XMk%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 25ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A16ZE1EQft&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=EBYQ%2BmvGOdl6C1fW2uvPjRS3XMk%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"EBYQ+mvGOdl6C1fW2uvPjRS3XMk=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:17:16ZE1EQft", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.7ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 62ms (ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.6ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 60ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A26Z1eD29V&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=MXD7sDIZw8q8tsYYlj%2FAsSmIHTg%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 27ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A26Z1eD29V&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=MXD7sDIZw8q8tsYYlj%2FAsSmIHTg%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"MXD7sDIZw8q8tsYYlj/AsSmIHTg=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:17:26Z1eD29V", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 61ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 11ms (Views: 10.5ms | ActiveRecord: 0.0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.7ms) Completed 200 OK in 10ms (Views: 9.6ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 06:18:07 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 06:18:07 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.8ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 26ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:18:07 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (6.2ms) session last_oidreq: session last_oidreq size: 804 session_id: d6218bef503e314e9d7332aad45fbbc9 session_id cookie: BAh7CSIQX2NzcmZfdG9rZW4iMXlHVTJMb2V0MUZ0ZEZRUVcyZityYkJtTFVBZWkxT0lJczNpRUE5cmpUQms9Ii5PcGVuSUQ6OkNvbnN1bWVyOjpsYXN0X3JlcXVlc3RlZF9lbmRwb2ludG86Ik9wZW5JRDo6T3BlbklEU2VydmljZUVuZHBvaW50DDoSQGNhbm9uaWNhbF9pZDA6EEBjbGFpbWVkX2lkMDoOQGxvY2FsX2lkMDoYQGRpc3BsYXlfaWRlbnRpZmllcjA6D0B0eXBlX3VyaXNbBiIsaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvc2VydmVyOhBAdXNlZF95YWRpc1Q6EEBzZXJ2ZXJfdXJsIiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyIg9zZXNzaW9uX2lkIiVkNjIxOGJlZjUwM2UzMTRlOWQ3MzMyYWFkNDVmYmJjOSI9T3BlbklEOjpDb25zdW1lcjo6RGlzY292ZXJlZFNlcnZpY2VzOjpPcGVuSUQ6OkNvbnN1bWVyOjpvOilPcGVuSUQ6OkNvbnN1bWVyOjpEaXNjb3ZlcmVkU2VydmljZXMJOhJAc3RhcnRpbmdfdXJsIipodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyL2lkcF94cmRzOg9AeWFkaXNfdXJsIipodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyL2lkcF94cmRzOg1AY3VycmVudEAJOg5Ac2VydmljZXNbAA==--41e24383267c05452a1bcd365b2ce4c9c5156926 Completed 200 OK in 24ms (Views: 16.2ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"yGU2Loet1FtdFQQW2f+rbBmLUAei1OIIs3iEA9rjTBk=", "yes"=>"yes", "id_to_send"=>"marcel"} session_id: d6218bef503e314e9d7332aad45fbbc9 session_id cookie: BAh7DCIuT3BlbklEOjpDb25zdW1lcjo6bGFzdF9yZXF1ZXN0ZWRfZW5kcG9pbnRvOiJPcGVuSUQ6Ok9wZW5JRFNlcnZpY2VFbmRwb2ludAw6DkBsb2NhbF9pZDA6GEBkaXNwbGF5X2lkZW50aWZpZXIwOg9AdHlwZV91cmlzWwYiLGh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL3NlcnZlcjoQQHVzZWRfeWFkaXNUOhBAc2VydmVyX3VybCIhaHR0cDovL2xvY2FsaG9zdDozMDA5L3NlcnZlcjoSQGNhbm9uaWNhbF9pZDA6EEBjbGFpbWVkX2lkMCIQX2NzcmZfdG9rZW4iMXlHVTJMb2V0MUZ0ZEZRUVcyZityYkJtTFVBZWkxT0lJczNpRUE5cmpUQms9Ig9zZXNzaW9uX2lkIiVkNjIxOGJlZjUwM2UzMTRlOWQ3MzMyYWFkNDVmYmJjOSIKaGVsbG8iCndvcmxkIj1PcGVuSUQ6OkNvbnN1bWVyOjpEaXNjb3ZlcmVkU2VydmljZXM6Ok9wZW5JRDo6Q29uc3VtZXI6Om86KU9wZW5JRDo6Q29uc3VtZXI6OkRpc2NvdmVyZWRTZXJ2aWNlcwk6D0B5YWRpc191cmwiKmh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIvaWRwX3hyZHM6DkBzZXJ2aWNlc1sAOhJAc3RhcnRpbmdfdXJsIipodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyL2lkcF94cmRzOg1AY3VycmVudEAHIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7GjoTQG9wZW5pZF9uc191cmlAHToKQGFyZ3N7DVsHQB0iCW1vZGUiEmNoZWNraWRfc2V0dXBbB0AdIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOx8iD2NvbnRyb2xsZXIiC3NlcnZlclsHQB0iEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQB0iDnJldHVybl90b0AZWwdAHSIKcmVhbG1AGFsHQB0iDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUA3OhJAYXNzb2NfaGFuZGxlQDA7DEAnOgpAbW9kZSISY2hlY2tpZF9zZXR1cDoRQG9wX2VuZHBvaW50IiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cw--279369ace44ed4ba1137444c001224c933b254aa hello: world last_oidreq: Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A18%3A11ZrhmBhZ&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=VeJwgcmZ8yfGmhLFDsQnLFt4E%2FA%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 14ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A18%3A11ZrhmBhZ&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=VeJwgcmZ8yfGmhLFDsQnLFt4E%2FA%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"VeJwgcmZ8yfGmhLFDsQnLFt4E/A=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:18:11ZrhmBhZ", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/marcel"} Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.7ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 42ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 7ms (Views: 6.8ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/rails.png" for 127.0.0.1 at Sun Mar 31 06:24:32 -0700 2013 NameError (undefined local variable or method `map' for #): config/routes.rb:2 config/routes.rb:1 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.7ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (18.2ms) Started GET "/" for 127.0.0.1 at Sun Mar 31 06:24:41 -0700 2013 ActionController::RoutingError (No route matches [GET] "/"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Connecting to database specified by database.yml Connecting to database specified by database.yml Connecting to database specified by database.yml Connecting to database specified by database.yml Started GET "/" for 127.0.0.1 at Sun Mar 31 06:28:03 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.3ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (27.7ms) Started GET "/" for 127.0.0.1 at Sun Mar 31 06:28:16 -0700 2013 Processing by LoginController#index as HTML Rendered login/index.html.erb within layouts/server (1.4ms) Completed 200 OK in 188ms (Views: 169.7ms | ActiveRecord: 0.0ms) Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:28:31 -0700 2013 Processing by ServerController#user_page as HTML Parameters: {"username"=>"marcel"} Rendered text template (0.0ms) Completed 200 OK in 32ms (Views: 29.7ms | ActiveRecord: 0.0ms) Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:28:53 -0700 2013 Processing by ServerController#user_page as HTML Parameters: {"username"=>"marcel"} Rendered text template (0.0ms) Completed 200 OK in 3ms (Views: 1.2ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:29:00 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel" for 127.0.0.1 at Sun Mar 31 06:29:10 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/user/marcel"} Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:29:10 -0700 2013 Processing by ServerController#user_page as application/xrds+xml Parameters: {"username"=>"marcel"} Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 157ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:29:10 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/marcel", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://localhost:3009/user/marcel"} Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.2ms) Completed 200 OK in 7ms (Views: 3.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"5AZtwrdNxknr4gvSZ1lKzmmJqX+iJdHapyEW/jkB90M=", "yes"=>"yes"} session_id: a0903f7e5c643a4e0ee0334fcb19b4c6 session_id cookie: BAh7CyIuT3BlbklEOjpDb25zdW1lcjo6bGFzdF9yZXF1ZXN0ZWRfZW5kcG9pbnRvOiJPcGVuSUQ6Ok9wZW5JRFNlcnZpY2VFbmRwb2ludAw6DkBsb2NhbF9pZDA6GEBkaXNwbGF5X2lkZW50aWZpZXIwOg9AdHlwZV91cmlzWwgiLGh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL3NpZ25vbiIhaHR0cDovL29wZW5pZC5uZXQvc2lnbm9uLzEuMCIfaHR0cDovL29wZW5pZC5uZXQvc3JlZy8xLjA6EEB1c2VkX3lhZGlzVDoQQHNlcnZlcl91cmwiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI6EkBjYW5vbmljYWxfaWQwOhBAY2xhaW1lZF9pZCImaHR0cDovL2xvY2FsaG9zdDozMDA5L3VzZXIvbWFyY2VsIhBfY3NyZl90b2tlbiIxNUFadHdyZE54a25yNGd2U1oxbEt6bW1KcVgraUpkSGFweUVXL2prQjkwTT0iD3Nlc3Npb25faWQiJWEwOTAzZjdlNWM2NDNhNGUwZWUwMzM0ZmNiMTliNGM2Ij1PcGVuSUQ6OkNvbnN1bWVyOjpEaXNjb3ZlcmVkU2VydmljZXM6Ok9wZW5JRDo6Q29uc3VtZXI6Om86KU9wZW5JRDo6Q29uc3VtZXI6OkRpc2NvdmVyZWRTZXJ2aWNlcwk6DkBzZXJ2aWNlc1sAOg1AY3VycmVudEAHOg9AeWFkaXNfdXJsIiZodHRwOi8vbG9jYWxob3N0OjMwMDkvdXNlci9tYXJjZWw6EkBzdGFydGluZ191cmwiJmh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS91c2VyL21hcmNlbCIQbGFzdF9vaWRyZXFvOiNPcGVuSUQ6OlNlcnZlcjo6Q2hlY2tJRFJlcXVlc3QOOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI6EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6DUBtZXNzYWdlbzoUT3BlbklEOjpNZXNzYWdlCDoTQG9wZW5pZF9uc191cmkiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQG5hbWVzcGFjZV90b19hbGlhc3sGIiVodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMDoTbnVsbF9uYW1lc3BhY2U6GEBhbGlhc190b19uYW1lc3BhY2V7BjsbQBw6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6CkBhcmdzew1bB0AcIgltb2RlIhJjaGVja2lkX3NldHVwWwdAHCIPY2xhaW1lZF9pZCImaHR0cDovL2xvY2FsaG9zdDozMDA5L3VzZXIvbWFyY2VsWwc6E2JhcmVfbmFtZXNwYWNlIg9jb250cm9sbGVyIgtzZXJ2ZXJbBzsfIgthY3Rpb24iCmluZGV4WwdAHCIRYXNzb2NfaGFuZGxlIiR7SE1BQy1TSEExfXs1MTU4MmQ5NH17Y2RrbzFnPT19WwdAHCIOcmV0dXJuX3RvIixodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXIvY29tcGxldGVbB0AcIgpyZWFsbUAaWwdAHCINaWRlbnRpdHkiJmh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS91c2VyL21hcmNlbDoPQHJldHVybl90b0A0OhJAYXNzb2NfaGFuZGxlQDE6D0BpbW1lZGlhdGVGOg5AaWRlbnRpdHlAOToKQG1vZGUiEmNoZWNraWRfc2V0dXA7DEAoIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cw--12967a41bad9d491f50492d6caaaef2b33acb4f6 hello: last_oidreq: Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A29%3A15Zsn1mhg&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=XUa1u9njJyD6Ji1pcDegIvvLCpI%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 13ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A29%3A15Zsn1mhg&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=XUa1u9njJyD6Ji1pcDegIvvLCpI%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"XUa1u9njJyD6Ji1pcDegIvvLCpI=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:29:15Zsn1mhg", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/marcel"} Redirected to http://localhost:3010/consumer Completed 302 Found in 12ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (1.4ms) Completed 200 OK in 9ms (Views: 8.3ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) ruby-openid-2.7.0debian.orig/examples/rails_openid/config/0000755000175000017500000000000012512544714023047 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/config/environment.rb0000644000175000017500000000023312512544714025736 0ustar sbadiasbadia# Load the rails application require File.expand_path('../application', __FILE__) # Initialize the rails application RailsOpenid::Application.initialize! ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/0000755000175000017500000000000012512544714025555 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/backtrace_silencers.rb0000644000175000017500000000062412512544714032072 0ustar sbadiasbadia# Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/inflections.rb0000644000175000017500000000102512512544714030415 0ustar sbadiasbadia# Be sure to restart your server when you modify this file. # Add new inflection rules using the following format # (all these examples are active by default): # ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end # # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections do |inflect| # inflect.acronym 'RESTful' # end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/session_store.rb0000644000175000017500000000065512512544714031007 0ustar sbadiasbadia# Be sure to restart your server when you modify this file. RailsOpenid::Application.config.session_store :cookie_store, :key => '_rails_openid_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") # RailsOpenid::Application.config.session_store :active_record_store ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/secret_token.rb0000644000175000017500000000076612512544714030600 0ustar sbadiasbadia# Be sure to restart your server when you modify this file. # Your secret key for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. RailsOpenid::Application.config.secret_token = '2314c4d00e3702d446505b8df2732c433379a0d61ac94c32a25f71612ab6df457bc9979eb32cae28ad6feacdd5a9ae7ac330934c5fb53877e02ce8e23ac0f494' ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/rails_root.rb0000644000175000017500000000003212512544714030252 0ustar sbadiasbadia::RAILS_ROOT = Rails.root ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/wrap_parameters.rb0000644000175000017500000000072412512544714031301 0ustar sbadiasbadia# Be sure to restart your server when you modify this file. # # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters :format => [:json] end # Disable root element in JSON by default. ActiveSupport.on_load(:active_record) do self.include_root_in_json = false end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/initializers/mime_types.rb0000644000175000017500000000031512512544714030254 0ustar sbadiasbadia# Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf # Mime::Type.register_alias "text/html", :iphone ruby-openid-2.7.0debian.orig/examples/rails_openid/config/routes.rb0000644000175000017500000000441012512544714024714 0ustar sbadiasbadiaRailsOpenid::Application.routes.draw do root :controller => 'login', :action => :index match 'server/xrds', :controller => 'server', :action => 'idp_xrds' match 'user/:username', :controller => 'server', :action => 'user_page' match 'user/:username/xrds', :controller => 'server', :action => 'user_xrds' # Allow downloading Web Service WSDL as a file with an extension # instead of a file named 'wsdl' match ':controller/service.wsdl', :action => 'wsdl' # Install the default route as the lowest priority. match ':controller/:action/:id' # The priority is based upon order of creation: # first created -> highest priority. # Sample of regular route: # match 'products/:id' => 'catalog#view' # Keep in mind you can assign values other than :controller and :action # Sample of named route: # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase # This route can be invoked with purchase_url(:id => product.id) # Sample resource route (maps HTTP verbs to controller actions automatically): # resources :products # Sample resource route with options: # resources :products do # member do # get 'short' # post 'toggle' # end # # collection do # get 'sold' # end # end # Sample resource route with sub-resources: # resources :products do # resources :comments, :sales # resource :seller # end # Sample resource route with more complex sub-resources # resources :products do # resources :comments # resources :sales do # get 'recent', :on => :collection # end # end # Sample resource route within a namespace: # namespace :admin do # # Directs /admin/products/* to Admin::ProductsController # # (app/controllers/admin/products_controller.rb) # resources :products # end # You can have the root of your site routed with "root" # just remember to delete public/index.html. # root :to => 'welcome#index' # See how all your routes lay out with "rake routes" # This is a legacy wild controller route that's not recommended for RESTful applications. # Note: This route will make all actions in every controller accessible via GET requests. match ':controller(/:action(/:id))(.:format)' end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/locales/0000755000175000017500000000000012512544714024471 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/config/locales/en.yml0000644000175000017500000000032612512544714025617 0ustar sbadiasbadia# Sample localization file for English. Add more files in this directory for other locales. # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. en: hello: "Hello world" ruby-openid-2.7.0debian.orig/examples/rails_openid/config/application.rb0000644000175000017500000000540012512544714025676 0ustar sbadiasbadiarequire File.expand_path('../boot', __FILE__) require 'rails/all' if defined?(Bundler) # If you precompile assets before deploying to production, use this line Bundler.require(*Rails.groups(:assets => %w(development test))) # If you want your assets lazily compiled in production, use this line # Bundler.require(:default, :assets, Rails.env) end module RailsOpenid class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. # config.autoload_paths += %W(#{config.root}/extras) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] # Activate observers that should always be running. # config.active_record.observers = :cacher, :garbage_collector, :forum_observer # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de # Configure the default encoding used in templates for Ruby 1.9. config.encoding = "utf-8" # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] # Enable escaping HTML in JSON. config.active_support.escape_html_entities_in_json = true # Use SQL instead of Active Record's schema dumper when creating the database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql # Enforce whitelist mode for mass assignment. # This will create an empty whitelist of attributes available for mass-assignment for all models # in your app. As such, your models will need to explicitly whitelist or blacklist accessible # parameters by using an attr_accessible or attr_protected declaration. config.active_record.whitelist_attributes = true # Enable the asset pipeline config.assets.enabled = true # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' end end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/environments/0000755000175000017500000000000012512544714025576 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/config/environments/test.rb0000644000175000017500000000277312512544714027113 0ustar sbadiasbadiaRailsOpenid::Application.configure do # Settings specified here will take precedence over those in config/application.rb # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true # Configure static asset server for tests with Cache-Control for performance config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" # Log error messages when you accidentally call methods on nil config.whiny_nils = true # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict # Print deprecation notices to the stderr config.active_support.deprecation = :stderr end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/environments/production.rb0000644000175000017500000000466512512544714030324 0ustar sbadiasbadiaRailsOpenid::Application.configure do # Settings specified here will take precedence over those in config/application.rb # Code is not reloaded between requests config.cache_classes = true # Full error reports are disabled and caching is turned on config.consider_all_requests_local = false config.action_controller.perform_caching = true # Disable Rails's static asset server (Apache or nginx will already do this) config.serve_static_assets = false # Compress JavaScripts and CSS config.assets.compress = true # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false # Generate digests for assets URLs config.assets.digest = true # Defaults to nil and saved in location specified by config.assets.prefix # config.assets.manifest = YOUR_PATH # Specifies the header that your server uses for sending files # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # See everything in the log (default is :info) # config.log_level = :debug # Prepend all log lines with the following tags # config.log_tags = [ :subdomain, :uuid ] # Use a different logger for distributed setups # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # Use a different cache store in production # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) # config.assets.precompile += %w( search.js ) # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false # Enable threaded mode # config.threadsafe! # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found) config.i18n.fallbacks = true # Send deprecation notices to registered listeners config.active_support.deprecation = :notify # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) # config.active_record.auto_explain_threshold_in_seconds = 0.5 end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/environments/development.rb0000644000175000017500000000254212512544714030450 0ustar sbadiasbadiaRailsOpenid::Application.configure do # Settings specified here will take precedence over those in config/application.rb # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false # Log error messages when you accidentally call methods on nil. config.whiny_nils = true # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false # Print deprecation notices to the Rails logger config.active_support.deprecation = :log # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin # Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) config.active_record.auto_explain_threshold_in_seconds = 0.5 # Do not compress assets config.assets.compress = false # Expands the lines which load the assets config.assets.debug = true end ruby-openid-2.7.0debian.orig/examples/rails_openid/config/database.yml0000644000175000017500000000110012512544714025326 0ustar sbadiasbadia# SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' development: adapter: sqlite3 database: db/development.sqlite3 pool: 5 timeout: 5000 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite3 database: db/test.sqlite3 pool: 5 timeout: 5000 production: adapter: sqlite3 database: db/production.sqlite3 pool: 5 timeout: 5000 ruby-openid-2.7.0debian.orig/examples/rails_openid/config/boot.rb0000644000175000017500000000027712512544714024345 0ustar sbadiasbadiarequire 'rubygems' # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) ruby-openid-2.7.0debian.orig/examples/rails_openid/Rakefile0000644000175000017500000000042412512544714023247 0ustar sbadiasbadia#!/usr/bin/env rake # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) RailsOpenid::Application.load_tasks ruby-openid-2.7.0debian.orig/examples/rails_openid/public/0000755000175000017500000000000012512544714023060 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/public/javascripts/0000755000175000017500000000000012512544714025411 5ustar sbadiasbadiaruby-openid-2.7.0debian.orig/examples/rails_openid/public/javascripts/application.js0000644000175000017500000000022412512544714030250 0ustar sbadiasbadia// Place your application-specific JavaScript functions and classes here // This file is automatically included by javascript_include_tag :defaults ruby-openid-2.7.0debian.orig/examples/rails_openid/public/javascripts/dragdrop.js0000644000175000017500000007457712512544714027575 0ustar sbadiasbadia// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ if(Object.isUndefined(Effect)) throw("dragdrop.js requires including script.aculo.us' effects.js library"); var Droppables = { drops: [], remove: function(element) { this.drops = this.drops.reject(function(d) { return d.element==$(element) }); }, add: function(element) { element = $(element); var options = Object.extend({ greedy: true, hoverclass: null, tree: false }, arguments[1] || { }); // cache containers if(options.containment) { options._containers = []; var containment = options.containment; if(Object.isArray(containment)) { containment.each( function(c) { options._containers.push($(c)) }); } else { options._containers.push($(containment)); } } if(options.accept) options.accept = [options.accept].flatten(); Element.makePositioned(element); // fix IE options.element = element; this.drops.push(options); }, findDeepestChild: function(drops) { deepest = drops[0]; for (i = 1; i < drops.length; ++i) if (Element.isParent(drops[i].element, deepest.element)) deepest = drops[i]; return deepest; }, isContained: function(element, drop) { var containmentNode; if(drop.tree) { containmentNode = element.treeNode; } else { containmentNode = element.parentNode; } return drop._containers.detect(function(c) { return containmentNode == c }); }, isAffected: function(point, element, drop) { return ( (drop.element!=element) && ((!drop._containers) || this.isContained(element, drop)) && ((!drop.accept) || (Element.classNames(element).detect( function(v) { return drop.accept.include(v) } ) )) && Position.within(drop.element, point[0], point[1]) ); }, deactivate: function(drop) { if(drop.hoverclass) Element.removeClassName(drop.element, drop.hoverclass); this.last_active = null; }, activate: function(drop) { if(drop.hoverclass) Element.addClassName(drop.element, drop.hoverclass); this.last_active = drop; }, show: function(point, element) { if(!this.drops.length) return; var drop, affected = []; this.drops.each( function(drop) { if(Droppables.isAffected(point, element, drop)) affected.push(drop); }); if(affected.length>0) drop = Droppables.findDeepestChild(affected); if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); if (drop) { Position.within(drop.element, point[0], point[1]); if(drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); if (drop != this.last_active) Droppables.activate(drop); } }, fire: function(event, element) { if(!this.last_active) return; Position.prepare(); if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) if (this.last_active.onDrop) { this.last_active.onDrop(element, this.last_active.element, event); return true; } }, reset: function() { if(this.last_active) this.deactivate(this.last_active); } }; var Draggables = { drags: [], observers: [], register: function(draggable) { if(this.drags.length == 0) { this.eventMouseUp = this.endDrag.bindAsEventListener(this); this.eventMouseMove = this.updateDrag.bindAsEventListener(this); this.eventKeypress = this.keyPress.bindAsEventListener(this); Event.observe(document, "mouseup", this.eventMouseUp); Event.observe(document, "mousemove", this.eventMouseMove); Event.observe(document, "keypress", this.eventKeypress); } this.drags.push(draggable); }, unregister: function(draggable) { this.drags = this.drags.reject(function(d) { return d==draggable }); if(this.drags.length == 0) { Event.stopObserving(document, "mouseup", this.eventMouseUp); Event.stopObserving(document, "mousemove", this.eventMouseMove); Event.stopObserving(document, "keypress", this.eventKeypress); } }, activate: function(draggable) { if(draggable.options.delay) { this._timeout = setTimeout(function() { Draggables._timeout = null; window.focus(); Draggables.activeDraggable = draggable; }.bind(this), draggable.options.delay); } else { window.focus(); // allows keypress events if window isn't currently focused, fails for Safari this.activeDraggable = draggable; } }, deactivate: function() { this.activeDraggable = null; }, updateDrag: function(event) { if(!this.activeDraggable) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; // Mozilla-based browsers fire successive mousemove events with // the same coordinates, prevent needless redrawing (moz bug?) if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; this._lastPointer = pointer; this.activeDraggable.updateDrag(event, pointer); }, endDrag: function(event) { if(this._timeout) { clearTimeout(this._timeout); this._timeout = null; } if(!this.activeDraggable) return; this._lastPointer = null; this.activeDraggable.endDrag(event); this.activeDraggable = null; }, keyPress: function(event) { if(this.activeDraggable) this.activeDraggable.keyPress(event); }, addObserver: function(observer) { this.observers.push(observer); this._cacheObserverCallbacks(); }, removeObserver: function(element) { // element instead of observer fixes mem leaks this.observers = this.observers.reject( function(o) { return o.element==element }); this._cacheObserverCallbacks(); }, notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' if(this[eventName+'Count'] > 0) this.observers.each( function(o) { if(o[eventName]) o[eventName](eventName, draggable, event); }); if(draggable.options[eventName]) draggable.options[eventName](draggable, event); }, _cacheObserverCallbacks: function() { ['onStart','onEnd','onDrag'].each( function(eventName) { Draggables[eventName+'Count'] = Draggables.observers.select( function(o) { return o[eventName]; } ).length; }); } }; /*--------------------------------------------------------------------------*/ var Draggable = Class.create({ initialize: function(element) { var defaults = { handle: false, reverteffect: function(element, top_offset, left_offset) { var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, queue: {scope:'_draggable', position:'end'} }); }, endeffect: function(element) { var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, queue: {scope:'_draggable', position:'end'}, afterFinish: function(){ Draggable._dragging[element] = false } }); }, zindex: 1000, revert: false, quiet: false, scroll: false, scrollSensitivity: 20, scrollSpeed: 15, snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } delay: 0 }; if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) Object.extend(defaults, { starteffect: function(element) { element._opacity = Element.getOpacity(element); Draggable._dragging[element] = true; new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); } }); var options = Object.extend(defaults, arguments[1] || { }); this.element = $(element); if(options.handle && Object.isString(options.handle)) this.handle = this.element.down('.'+options.handle, 0); if(!this.handle) this.handle = $(options.handle); if(!this.handle) this.handle = this.element; if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { options.scroll = $(options.scroll); this._isScrollChild = Element.childOf(this.element, options.scroll); } Element.makePositioned(this.element); // fix IE this.options = options; this.dragging = false; this.eventMouseDown = this.initDrag.bindAsEventListener(this); Event.observe(this.handle, "mousedown", this.eventMouseDown); Draggables.register(this); }, destroy: function() { Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); Draggables.unregister(this); }, currentDelta: function() { return([ parseInt(Element.getStyle(this.element,'left') || '0'), parseInt(Element.getStyle(this.element,'top') || '0')]); }, initDrag: function(event) { if(!Object.isUndefined(Draggable._dragging[this.element]) && Draggable._dragging[this.element]) return; if(Event.isLeftClick(event)) { // abort on form elements, fixes a Firefox issue var src = Event.element(event); if((tag_name = src.tagName.toUpperCase()) && ( tag_name=='INPUT' || tag_name=='SELECT' || tag_name=='OPTION' || tag_name=='BUTTON' || tag_name=='TEXTAREA')) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; var pos = Position.cumulativeOffset(this.element); this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); Draggables.activate(this); Event.stop(event); } }, startDrag: function(event) { this.dragging = true; if(!this.delta) this.delta = this.currentDelta(); if(this.options.zindex) { this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); this.element.style.zIndex = this.options.zindex; } if(this.options.ghosting) { this._clone = this.element.cloneNode(true); this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); if (!this._originallyAbsolute) Position.absolutize(this.element); this.element.parentNode.insertBefore(this._clone, this.element); } if(this.options.scroll) { if (this.options.scroll == window) { var where = this._getWindowScroll(this.options.scroll); this.originalScrollLeft = where.left; this.originalScrollTop = where.top; } else { this.originalScrollLeft = this.options.scroll.scrollLeft; this.originalScrollTop = this.options.scroll.scrollTop; } } Draggables.notify('onStart', this, event); if(this.options.starteffect) this.options.starteffect(this.element); }, updateDrag: function(event, pointer) { if(!this.dragging) this.startDrag(event); if(!this.options.quiet){ Position.prepare(); Droppables.show(pointer, this.element); } Draggables.notify('onDrag', this, event); this.draw(pointer); if(this.options.change) this.options.change(this); if(this.options.scroll) { this.stopScrolling(); var p; if (this.options.scroll == window) { with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } } else { p = Position.page(this.options.scroll); p[0] += this.options.scroll.scrollLeft + Position.deltaX; p[1] += this.options.scroll.scrollTop + Position.deltaY; p.push(p[0]+this.options.scroll.offsetWidth); p.push(p[1]+this.options.scroll.offsetHeight); } var speed = [0,0]; if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); this.startScrolling(speed); } // fix AppleWebKit rendering if(Prototype.Browser.WebKit) window.scrollBy(0,0); Event.stop(event); }, finishDrag: function(event, success) { this.dragging = false; if(this.options.quiet){ Position.prepare(); var pointer = [Event.pointerX(event), Event.pointerY(event)]; Droppables.show(pointer, this.element); } if(this.options.ghosting) { if (!this._originallyAbsolute) Position.relativize(this.element); delete this._originallyAbsolute; Element.remove(this._clone); this._clone = null; } var dropped = false; if(success) { dropped = Droppables.fire(event, this.element); if (!dropped) dropped = false; } if(dropped && this.options.onDropped) this.options.onDropped(this.element); Draggables.notify('onEnd', this, event); var revert = this.options.revert; if(revert && Object.isFunction(revert)) revert = revert(this.element); var d = this.currentDelta(); if(revert && this.options.reverteffect) { if (dropped == 0 || revert != 'failure') this.options.reverteffect(this.element, d[1]-this.delta[1], d[0]-this.delta[0]); } else { this.delta = d; } if(this.options.zindex) this.element.style.zIndex = this.originalZ; if(this.options.endeffect) this.options.endeffect(this.element); Draggables.deactivate(this); Droppables.reset(); }, keyPress: function(event) { if(event.keyCode!=Event.KEY_ESC) return; this.finishDrag(event, false); Event.stop(event); }, endDrag: function(event) { if(!this.dragging) return; this.stopScrolling(); this.finishDrag(event, true); Event.stop(event); }, draw: function(point) { var pos = Position.cumulativeOffset(this.element); if(this.options.ghosting) { var r = Position.realOffset(this.element); pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; } var d = this.currentDelta(); pos[0] -= d[0]; pos[1] -= d[1]; if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; } var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this)); if(this.options.snap) { if(Object.isFunction(this.options.snap)) { p = this.options.snap(p[0],p[1],this); } else { if(Object.isArray(this.options.snap)) { p = p.map( function(v, i) { return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)); } else { p = p.map( function(v) { return (v/this.options.snap).round()*this.options.snap }.bind(this)); } }} var style = this.element.style; if((!this.options.constraint) || (this.options.constraint=='horizontal')) style.left = p[0] + "px"; if((!this.options.constraint) || (this.options.constraint=='vertical')) style.top = p[1] + "px"; if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering }, stopScrolling: function() { if(this.scrollInterval) { clearInterval(this.scrollInterval); this.scrollInterval = null; Draggables._lastScrollPointer = null; } }, startScrolling: function(speed) { if(!(speed[0] || speed[1])) return; this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; this.lastScrolled = new Date(); this.scrollInterval = setInterval(this.scroll.bind(this), 10); }, scroll: function() { var current = new Date(); var delta = current - this.lastScrolled; this.lastScrolled = current; if(this.options.scroll == window) { with (this._getWindowScroll(this.options.scroll)) { if (this.scrollSpeed[0] || this.scrollSpeed[1]) { var d = delta / 1000; this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); } } } else { this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; } Position.prepare(); Droppables.show(Draggables._lastPointer, this.element); Draggables.notify('onDrag', this); if (this._isScrollChild) { Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; if (Draggables._lastScrollPointer[0] < 0) Draggables._lastScrollPointer[0] = 0; if (Draggables._lastScrollPointer[1] < 0) Draggables._lastScrollPointer[1] = 0; this.draw(Draggables._lastScrollPointer); } if(this.options.change) this.options.change(this); }, _getWindowScroll: function(w) { var T, L, W, H; with (w.document) { if (w.document.documentElement && documentElement.scrollTop) { T = documentElement.scrollTop; L = documentElement.scrollLeft; } else if (w.document.body) { T = body.scrollTop; L = body.scrollLeft; } if (w.innerWidth) { W = w.innerWidth; H = w.innerHeight; } else if (w.document.documentElement && documentElement.clientWidth) { W = documentElement.clientWidth; H = documentElement.clientHeight; } else { W = body.offsetWidth; H = body.offsetHeight; } } return { top: T, left: L, width: W, height: H }; } }); Draggable._dragging = { }; /*--------------------------------------------------------------------------*/ var SortableObserver = Class.create({ initialize: function(element, observer) { this.element = $(element); this.observer = observer; this.lastValue = Sortable.serialize(this.element); }, onStart: function() { this.lastValue = Sortable.serialize(this.element); }, onEnd: function() { Sortable.unmark(); if(this.lastValue != Sortable.serialize(this.element)) this.observer(this.element) } }); var Sortable = { SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, sortables: { }, _findRootElement: function(element) { while (element.tagName.toUpperCase() != "BODY") { if(element.id && Sortable.sortables[element.id]) return element; element = element.parentNode; } }, options: function(element) { element = Sortable._findRootElement($(element)); if(!element) return; return Sortable.sortables[element.id]; }, destroy: function(element){ element = $(element); var s = Sortable.sortables[element.id]; if(s) { Draggables.removeObserver(s.element); s.droppables.each(function(d){ Droppables.remove(d) }); s.draggables.invoke('destroy'); delete Sortable.sortables[s.element.id]; } }, create: function(element) { element = $(element); var options = Object.extend({ element: element, tag: 'li', // assumes li children, override with tag: 'tagname' dropOnEmpty: false, tree: false, treeTag: 'ul', overlap: 'vertical', // one of 'vertical', 'horizontal' constraint: 'vertical', // one of 'vertical', 'horizontal', false containment: element, // also takes array of elements (or id's); or false handle: false, // or a CSS class only: false, delay: 0, hoverclass: null, ghosting: false, quiet: false, scroll: false, scrollSensitivity: 20, scrollSpeed: 15, format: this.SERIALIZE_RULE, // these take arrays of elements or ids and can be // used for better initialization performance elements: false, handles: false, onChange: Prototype.emptyFunction, onUpdate: Prototype.emptyFunction }, arguments[1] || { }); // clear any old sortable with same element this.destroy(element); // build options for the draggables var options_for_draggable = { revert: true, quiet: options.quiet, scroll: options.scroll, scrollSpeed: options.scrollSpeed, scrollSensitivity: options.scrollSensitivity, delay: options.delay, ghosting: options.ghosting, constraint: options.constraint, handle: options.handle }; if(options.starteffect) options_for_draggable.starteffect = options.starteffect; if(options.reverteffect) options_for_draggable.reverteffect = options.reverteffect; else if(options.ghosting) options_for_draggable.reverteffect = function(element) { element.style.top = 0; element.style.left = 0; }; if(options.endeffect) options_for_draggable.endeffect = options.endeffect; if(options.zindex) options_for_draggable.zindex = options.zindex; // build options for the droppables var options_for_droppable = { overlap: options.overlap, containment: options.containment, tree: options.tree, hoverclass: options.hoverclass, onHover: Sortable.onHover }; var options_for_tree = { onHover: Sortable.onEmptyHover, overlap: options.overlap, containment: options.containment, hoverclass: options.hoverclass }; // fix for gecko engine Element.cleanWhitespace(element); options.draggables = []; options.droppables = []; // drop on empty handling if(options.dropOnEmpty || options.tree) { Droppables.add(element, options_for_tree); options.droppables.push(element); } (options.elements || this.findElements(element, options) || []).each( function(e,i) { var handle = options.handles ? $(options.handles[i]) : (options.handle ? $(e).select('.' + options.handle)[0] : e); options.draggables.push( new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); Droppables.add(e, options_for_droppable); if(options.tree) e.treeNode = element; options.droppables.push(e); }); if(options.tree) { (Sortable.findTreeElements(element, options) || []).each( function(e) { Droppables.add(e, options_for_tree); e.treeNode = element; options.droppables.push(e); }); } // keep reference this.sortables[element.id] = options; // for onupdate Draggables.addObserver(new SortableObserver(element, options.onUpdate)); }, // return all suitable-for-sortable elements in a guaranteed order findElements: function(element, options) { return Element.findChildren( element, options.only, options.tree ? true : false, options.tag); }, findTreeElements: function(element, options) { return Element.findChildren( element, options.only, options.tree ? true : false, options.treeTag); }, onHover: function(element, dropon, overlap) { if(Element.isParent(dropon, element)) return; if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { return; } else if(overlap>0.5) { Sortable.mark(dropon, 'before'); if(dropon.previousSibling != element) { var oldParentNode = element.parentNode; element.style.visibility = "hidden"; // fix gecko rendering dropon.parentNode.insertBefore(element, dropon); if(dropon.parentNode!=oldParentNode) Sortable.options(oldParentNode).onChange(element); Sortable.options(dropon.parentNode).onChange(element); } } else { Sortable.mark(dropon, 'after'); var nextElement = dropon.nextSibling || null; if(nextElement != element) { var oldParentNode = element.parentNode; element.style.visibility = "hidden"; // fix gecko rendering dropon.parentNode.insertBefore(element, nextElement); if(dropon.parentNode!=oldParentNode) Sortable.options(oldParentNode).onChange(element); Sortable.options(dropon.parentNode).onChange(element); } } }, onEmptyHover: function(element, dropon, overlap) { var oldParentNode = element.parentNode; var droponOptions = Sortable.options(dropon); if(!Element.isParent(dropon, element)) { var index; var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); var child = null; if(children) { var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); for (index = 0; index < children.length; index += 1) { if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { offset -= Element.offsetSize (children[index], droponOptions.overlap); } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { child = index + 1 < children.length ? children[index + 1] : null; break; } else { child = children[index]; break; } } } dropon.insertBefore(element, child); Sortable.options(oldParentNode).onChange(element); droponOptions.onChange(element); } }, unmark: function() { if(Sortable._marker) Sortable._marker.hide(); }, mark: function(dropon, position) { // mark on ghosting only var sortable = Sortable.options(dropon.parentNode); if(sortable && !sortable.ghosting) return; if(!Sortable._marker) { Sortable._marker = ($('dropmarker') || Element.extend(document.createElement('DIV'))). hide().addClassName('dropmarker').setStyle({position:'absolute'}); document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); } var offsets = Position.cumulativeOffset(dropon); Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); if(position=='after') if(sortable.overlap == 'horizontal') Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); else Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); Sortable._marker.show(); }, _tree: function(element, options, parent) { var children = Sortable.findElements(element, options) || []; for (var i = 0; i < children.length; ++i) { var match = children[i].id.match(options.format); if (!match) continue; var child = { id: encodeURIComponent(match ? match[1] : null), element: element, parent: parent, children: [], position: parent.children.length, container: $(children[i]).down(options.treeTag) }; /* Get the element containing the children and recurse over it */ if (child.container) this._tree(child.container, options, child); parent.children.push (child); } return parent; }, tree: function(element) { element = $(element); var sortableOptions = this.options(element); var options = Object.extend({ tag: sortableOptions.tag, treeTag: sortableOptions.treeTag, only: sortableOptions.only, name: element.id, format: sortableOptions.format }, arguments[1] || { }); var root = { id: null, parent: null, children: [], container: element, position: 0 }; return Sortable._tree(element, options, root); }, /* Construct a [i] index for a particular node */ _constructIndex: function(node) { var index = ''; do { if (node.id) index = '[' + node.position + ']' + index; } while ((node = node.parent) != null); return index; }, sequence: function(element) { element = $(element); var options = Object.extend(this.options(element), arguments[1] || { }); return $(this.findElements(element, options) || []).map( function(item) { return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; }); }, setSequence: function(element, new_sequence) { element = $(element); var options = Object.extend(this.options(element), arguments[2] || { }); var nodeMap = { }; this.findElements(element, options).each( function(n) { if (n.id.match(options.format)) nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; n.parentNode.removeChild(n); }); new_sequence.each(function(ident) { var n = nodeMap[ident]; if (n) { n[1].appendChild(n[0]); delete nodeMap[ident]; } }); }, serialize: function(element) { element = $(element); var options = Object.extend(Sortable.options(element), arguments[1] || { }); var name = encodeURIComponent( (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); if (options.tree) { return Sortable.tree(element, arguments[1]).children.map( function (item) { return [name + Sortable._constructIndex(item) + "[id]=" + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); }).flatten().join('&'); } else { return Sortable.sequence(element, arguments[1]).map( function(item) { return name + "[]=" + encodeURIComponent(item); }).join('&'); } } }; // Returns true if child is contained within element Element.isParent = function(child, element) { if (!child.parentNode || child == element) return false; if (child.parentNode == element) return true; return Element.isParent(child.parentNode, element); }; Element.findChildren = function(element, only, recursive, tagName) { if(!element.hasChildNodes()) return null; tagName = tagName.toUpperCase(); if(only) only = [only].flatten(); var elements = []; $A(element.childNodes).each( function(e) { if(e.tagName && e.tagName.toUpperCase()==tagName && (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) elements.push(e); if(recursive) { var grandchildren = Element.findChildren(e, only, recursive, tagName); if(grandchildren) elements.push(grandchildren); } }); return (elements.length>0 ? elements.flatten() : []); }; Element.offsetSize = function (element, type) { return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; };ruby-openid-2.7.0debian.orig/examples/rails_openid/public/javascripts/controls.js0000644000175000017500000010363412512544714027621 0ustar sbadiasbadia// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan) // (c) 2005-2008 Jon Tirsen (http://www.tirsen.com) // Contributors: // Richard Livsey // Rahul Bhargava // Rob Wills // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ // Autocompleter.Base handles all the autocompletion functionality // that's independent of the data source for autocompletion. This // includes drawing the autocompletion menu, observing keyboard // and mouse events, and similar. // // Specific autocompleters need to provide, at the very least, // a getUpdatedChoices function that will be invoked every time // the text inside the monitored textbox changes. This method // should get the text for which to provide autocompletion by // invoking this.getToken(), NOT by directly accessing // this.element.value. This is to allow incremental tokenized // autocompletion. Specific auto-completion logic (AJAX, etc) // belongs in getUpdatedChoices. // // Tokenized incremental autocompletion is enabled automatically // when an autocompleter is instantiated with the 'tokens' option // in the options parameter, e.g.: // new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); // will incrementally autocomplete with a comma as the token. // Additionally, ',' in the above example can be replaced with // a token array, e.g. { tokens: [',', '\n'] } which // enables autocompletion on multiple tokens. This is most // useful when one of the tokens is \n (a newline), as it // allows smart autocompletion after linebreaks. if(typeof Effect == 'undefined') throw("controls.js requires including script.aculo.us' effects.js library"); var Autocompleter = { }; Autocompleter.Base = Class.create({ baseInitialize: function(element, update, options) { element = $(element); this.element = element; this.update = $(update); this.hasFocus = false; this.changed = false; this.active = false; this.index = 0; this.entryCount = 0; this.oldElementValue = this.element.value; if(this.setOptions) this.setOptions(options); else this.options = options || { }; this.options.paramName = this.options.paramName || this.element.name; this.options.tokens = this.options.tokens || []; this.options.frequency = this.options.frequency || 0.4; this.options.minChars = this.options.minChars || 1; this.options.onShow = this.options.onShow || function(element, update){ if(!update.style.position || update.style.position=='absolute') { update.style.position = 'absolute'; Position.clone(element, update, { setHeight: false, offsetTop: element.offsetHeight }); } Effect.Appear(update,{duration:0.15}); }; this.options.onHide = this.options.onHide || function(element, update){ new Effect.Fade(update,{duration:0.15}) }; if(typeof(this.options.tokens) == 'string') this.options.tokens = new Array(this.options.tokens); // Force carriage returns as token delimiters anyway if (!this.options.tokens.include('\n')) this.options.tokens.push('\n'); this.observer = null; this.element.setAttribute('autocomplete','off'); Element.hide(this.update); Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); }, show: function() { if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); if(!this.iefix && (Prototype.Browser.IE) && (Element.getStyle(this.update, 'position')=='absolute')) { new Insertion.After(this.update, ''); this.iefix = $(this.update.id+'_iefix'); } if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); }, fixIEOverlapping: function() { Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); this.iefix.style.zIndex = 1; this.update.style.zIndex = 2; Element.show(this.iefix); }, hide: function() { this.stopIndicator(); if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); if(this.iefix) Element.hide(this.iefix); }, startIndicator: function() { if(this.options.indicator) Element.show(this.options.indicator); }, stopIndicator: function() { if(this.options.indicator) Element.hide(this.options.indicator); }, onKeyPress: function(event) { if(this.active) switch(event.keyCode) { case Event.KEY_TAB: case Event.KEY_RETURN: this.selectEntry(); Event.stop(event); case Event.KEY_ESC: this.hide(); this.active = false; Event.stop(event); return; case Event.KEY_LEFT: case Event.KEY_RIGHT: return; case Event.KEY_UP: this.markPrevious(); this.render(); Event.stop(event); return; case Event.KEY_DOWN: this.markNext(); this.render(); Event.stop(event); return; } else if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; this.changed = true; this.hasFocus = true; if(this.observer) clearTimeout(this.observer); this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); }, activate: function() { this.changed = false; this.hasFocus = true; this.getUpdatedChoices(); }, onHover: function(event) { var element = Event.findElement(event, 'LI'); if(this.index != element.autocompleteIndex) { this.index = element.autocompleteIndex; this.render(); } Event.stop(event); }, onClick: function(event) { var element = Event.findElement(event, 'LI'); this.index = element.autocompleteIndex; this.selectEntry(); this.hide(); }, onBlur: function(event) { // needed to make click events working setTimeout(this.hide.bind(this), 250); this.hasFocus = false; this.active = false; }, render: function() { if(this.entryCount > 0) { for (var i = 0; i < this.entryCount; i++) this.index==i ? Element.addClassName(this.getEntry(i),"selected") : Element.removeClassName(this.getEntry(i),"selected"); if(this.hasFocus) { this.show(); this.active = true; } } else { this.active = false; this.hide(); } }, markPrevious: function() { if(this.index > 0) this.index--; else this.index = this.entryCount-1; this.getEntry(this.index).scrollIntoView(true); }, markNext: function() { if(this.index < this.entryCount-1) this.index++; else this.index = 0; this.getEntry(this.index).scrollIntoView(false); }, getEntry: function(index) { return this.update.firstChild.childNodes[index]; }, getCurrentEntry: function() { return this.getEntry(this.index); }, selectEntry: function() { this.active = false; this.updateElement(this.getCurrentEntry()); }, updateElement: function(selectedElement) { if (this.options.updateElement) { this.options.updateElement(selectedElement); return; } var value = ''; if (this.options.select) { var nodes = $(selectedElement).select('.' + this.options.select) || []; if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); } else value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); var bounds = this.getTokenBounds(); if (bounds[0] != -1) { var newValue = this.element.value.substr(0, bounds[0]); var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); if (whitespace) newValue += whitespace[0]; this.element.value = newValue + value + this.element.value.substr(bounds[1]); } else { this.element.value = value; } this.oldElementValue = this.element.value; this.element.focus(); if (this.options.afterUpdateElement) this.options.afterUpdateElement(this.element, selectedElement); }, updateChoices: function(choices) { if(!this.changed && this.hasFocus) { this.update.innerHTML = choices; Element.cleanWhitespace(this.update); Element.cleanWhitespace(this.update.down()); if(this.update.firstChild && this.update.down().childNodes) { this.entryCount = this.update.down().childNodes.length; for (var i = 0; i < this.entryCount; i++) { var entry = this.getEntry(i); entry.autocompleteIndex = i; this.addObservers(entry); } } else { this.entryCount = 0; } this.stopIndicator(); this.index = 0; if(this.entryCount==1 && this.options.autoSelect) { this.selectEntry(); this.hide(); } else { this.render(); } } }, addObservers: function(element) { Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); Event.observe(element, "click", this.onClick.bindAsEventListener(this)); }, onObserverEvent: function() { this.changed = false; this.tokenBounds = null; if(this.getToken().length>=this.options.minChars) { this.getUpdatedChoices(); } else { this.active = false; this.hide(); } this.oldElementValue = this.element.value; }, getToken: function() { var bounds = this.getTokenBounds(); return this.element.value.substring(bounds[0], bounds[1]).strip(); }, getTokenBounds: function() { if (null != this.tokenBounds) return this.tokenBounds; var value = this.element.value; if (value.strip().empty()) return [-1, 0]; var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); var offset = (diff == this.oldElementValue.length ? 1 : 0); var prevTokenPos = -1, nextTokenPos = value.length; var tp; for (var index = 0, l = this.options.tokens.length; index < l; ++index) { tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); if (tp > prevTokenPos) prevTokenPos = tp; tp = value.indexOf(this.options.tokens[index], diff + offset); if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; } return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); } }); Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { var boundary = Math.min(newS.length, oldS.length); for (var index = 0; index < boundary; ++index) if (newS[index] != oldS[index]) return index; return boundary; }; Ajax.Autocompleter = Class.create(Autocompleter.Base, { initialize: function(element, update, url, options) { this.baseInitialize(element, update, options); this.options.asynchronous = true; this.options.onComplete = this.onComplete.bind(this); this.options.defaultParams = this.options.parameters || null; this.url = url; }, getUpdatedChoices: function() { this.startIndicator(); var entry = encodeURIComponent(this.options.paramName) + '=' + encodeURIComponent(this.getToken()); this.options.parameters = this.options.callback ? this.options.callback(this.element, entry) : entry; if(this.options.defaultParams) this.options.parameters += '&' + this.options.defaultParams; new Ajax.Request(this.url, this.options); }, onComplete: function(request) { this.updateChoices(request.responseText); } }); // The local array autocompleter. Used when you'd prefer to // inject an array of autocompletion options into the page, rather // than sending out Ajax queries, which can be quite slow sometimes. // // The constructor takes four parameters. The first two are, as usual, // the id of the monitored textbox, and id of the autocompletion menu. // The third is the array you want to autocomplete from, and the fourth // is the options block. // // Extra local autocompletion options: // - choices - How many autocompletion choices to offer // // - partialSearch - If false, the autocompleter will match entered // text only at the beginning of strings in the // autocomplete array. Defaults to true, which will // match text at the beginning of any *word* in the // strings in the autocomplete array. If you want to // search anywhere in the string, additionally set // the option fullSearch to true (default: off). // // - fullSsearch - Search anywhere in autocomplete array strings. // // - partialChars - How many characters to enter before triggering // a partial match (unlike minChars, which defines // how many characters are required to do any match // at all). Defaults to 2. // // - ignoreCase - Whether to ignore case when autocompleting. // Defaults to true. // // It's possible to pass in a custom function as the 'selector' // option, if you prefer to write your own autocompletion logic. // In that case, the other options above will not apply unless // you support them. Autocompleter.Local = Class.create(Autocompleter.Base, { initialize: function(element, update, array, options) { this.baseInitialize(element, update, options); this.options.array = array; }, getUpdatedChoices: function() { this.updateChoices(this.options.selector(this)); }, setOptions: function(options) { this.options = Object.extend({ choices: 10, partialSearch: true, partialChars: 2, ignoreCase: true, fullSearch: false, selector: function(instance) { var ret = []; // Beginning matches var partial = []; // Inside matches var entry = instance.getToken(); var count = 0; for (var i = 0; i < instance.options.array.length && ret.length < instance.options.choices ; i++) { var elem = instance.options.array[i]; var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf(entry); while (foundPos != -1) { if (foundPos == 0 && elem.length != entry.length) { ret.push("
  • " + elem.substr(0, entry.length) + "" + elem.substr(entry.length) + "
  • "); break; } else if (entry.length >= instance.options.partialChars && instance.options.partialSearch && foundPos != -1) { if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { partial.push("
  • " + elem.substr(0, foundPos) + "" + elem.substr(foundPos, entry.length) + "" + elem.substr( foundPos + entry.length) + "
  • "); break; } } foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : elem.indexOf(entry, foundPos + 1); } } if (partial.length) ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); return "
      " + ret.join('') + "
    "; } }, options || { }); } }); // AJAX in-place editor and collection editor // Full rewrite by Christophe Porteneuve (April 2007). // Use this if you notice weird scrolling problems on some browsers, // the DOM might be a bit confused when this gets called so do this // waits 1 ms (with setTimeout) until it does the activation Field.scrollFreeActivate = function(field) { setTimeout(function() { Field.activate(field); }, 1); }; Ajax.InPlaceEditor = Class.create({ initialize: function(element, url, options) { this.url = url; this.element = element = $(element); this.prepareOptions(); this._controls = { }; arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! Object.extend(this.options, options || { }); if (!this.options.formId && this.element.id) { this.options.formId = this.element.id + '-inplaceeditor'; if ($(this.options.formId)) this.options.formId = ''; } if (this.options.externalControl) this.options.externalControl = $(this.options.externalControl); if (!this.options.externalControl) this.options.externalControlOnly = false; this._originalBackground = this.element.getStyle('background-color') || 'transparent'; this.element.title = this.options.clickToEditText; this._boundCancelHandler = this.handleFormCancellation.bind(this); this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); this._boundFailureHandler = this.handleAJAXFailure.bind(this); this._boundSubmitHandler = this.handleFormSubmission.bind(this); this._boundWrapperHandler = this.wrapUp.bind(this); this.registerListeners(); }, checkForEscapeOrReturn: function(e) { if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; if (Event.KEY_ESC == e.keyCode) this.handleFormCancellation(e); else if (Event.KEY_RETURN == e.keyCode) this.handleFormSubmission(e); }, createControl: function(mode, handler, extraClasses) { var control = this.options[mode + 'Control']; var text = this.options[mode + 'Text']; if ('button' == control) { var btn = document.createElement('input'); btn.type = 'submit'; btn.value = text; btn.className = 'editor_' + mode + '_button'; if ('cancel' == mode) btn.onclick = this._boundCancelHandler; this._form.appendChild(btn); this._controls[mode] = btn; } else if ('link' == control) { var link = document.createElement('a'); link.href = '#'; link.appendChild(document.createTextNode(text)); link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; link.className = 'editor_' + mode + '_link'; if (extraClasses) link.className += ' ' + extraClasses; this._form.appendChild(link); this._controls[mode] = link; } }, createEditField: function() { var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); var fld; if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { fld = document.createElement('input'); fld.type = 'text'; var size = this.options.size || this.options.cols || 0; if (0 < size) fld.size = size; } else { fld = document.createElement('textarea'); fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); fld.cols = this.options.cols || 40; } fld.name = this.options.paramName; fld.value = text; // No HTML breaks conversion anymore fld.className = 'editor_field'; if (this.options.submitOnBlur) fld.onblur = this._boundSubmitHandler; this._controls.editor = fld; if (this.options.loadTextURL) this.loadExternalText(); this._form.appendChild(this._controls.editor); }, createForm: function() { var ipe = this; function addText(mode, condition) { var text = ipe.options['text' + mode + 'Controls']; if (!text || condition === false) return; ipe._form.appendChild(document.createTextNode(text)); }; this._form = $(document.createElement('form')); this._form.id = this.options.formId; this._form.addClassName(this.options.formClassName); this._form.onsubmit = this._boundSubmitHandler; this.createEditField(); if ('textarea' == this._controls.editor.tagName.toLowerCase()) this._form.appendChild(document.createElement('br')); if (this.options.onFormCustomization) this.options.onFormCustomization(this, this._form); addText('Before', this.options.okControl || this.options.cancelControl); this.createControl('ok', this._boundSubmitHandler); addText('Between', this.options.okControl && this.options.cancelControl); this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); addText('After', this.options.okControl || this.options.cancelControl); }, destroy: function() { if (this._oldInnerHTML) this.element.innerHTML = this._oldInnerHTML; this.leaveEditMode(); this.unregisterListeners(); }, enterEditMode: function(e) { if (this._saving || this._editing) return; this._editing = true; this.triggerCallback('onEnterEditMode'); if (this.options.externalControl) this.options.externalControl.hide(); this.element.hide(); this.createForm(); this.element.parentNode.insertBefore(this._form, this.element); if (!this.options.loadTextURL) this.postProcessEditField(); if (e) Event.stop(e); }, enterHover: function(e) { if (this.options.hoverClassName) this.element.addClassName(this.options.hoverClassName); if (this._saving) return; this.triggerCallback('onEnterHover'); }, getText: function() { return this.element.innerHTML.unescapeHTML(); }, handleAJAXFailure: function(transport) { this.triggerCallback('onFailure', transport); if (this._oldInnerHTML) { this.element.innerHTML = this._oldInnerHTML; this._oldInnerHTML = null; } }, handleFormCancellation: function(e) { this.wrapUp(); if (e) Event.stop(e); }, handleFormSubmission: function(e) { var form = this._form; var value = $F(this._controls.editor); this.prepareSubmission(); var params = this.options.callback(form, value) || ''; if (Object.isString(params)) params = params.toQueryParams(); params.editorId = this.element.id; if (this.options.htmlResponse) { var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, onFailure: this._boundFailureHandler }); new Ajax.Updater({ success: this.element }, this.url, options); } else { var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, onFailure: this._boundFailureHandler }); new Ajax.Request(this.url, options); } if (e) Event.stop(e); }, leaveEditMode: function() { this.element.removeClassName(this.options.savingClassName); this.removeForm(); this.leaveHover(); this.element.style.backgroundColor = this._originalBackground; this.element.show(); if (this.options.externalControl) this.options.externalControl.show(); this._saving = false; this._editing = false; this._oldInnerHTML = null; this.triggerCallback('onLeaveEditMode'); }, leaveHover: function(e) { if (this.options.hoverClassName) this.element.removeClassName(this.options.hoverClassName); if (this._saving) return; this.triggerCallback('onLeaveHover'); }, loadExternalText: function() { this._form.addClassName(this.options.loadingClassName); this._controls.editor.disabled = true; var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { this._form.removeClassName(this.options.loadingClassName); var text = transport.responseText; if (this.options.stripLoadedTextTags) text = text.stripTags(); this._controls.editor.value = text; this._controls.editor.disabled = false; this.postProcessEditField(); }.bind(this), onFailure: this._boundFailureHandler }); new Ajax.Request(this.options.loadTextURL, options); }, postProcessEditField: function() { var fpc = this.options.fieldPostCreation; if (fpc) $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); }, prepareOptions: function() { this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); [this._extraDefaultOptions].flatten().compact().each(function(defs) { Object.extend(this.options, defs); }.bind(this)); }, prepareSubmission: function() { this._saving = true; this.removeForm(); this.leaveHover(); this.showSaving(); }, registerListeners: function() { this._listeners = { }; var listener; $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { listener = this[pair.value].bind(this); this._listeners[pair.key] = listener; if (!this.options.externalControlOnly) this.element.observe(pair.key, listener); if (this.options.externalControl) this.options.externalControl.observe(pair.key, listener); }.bind(this)); }, removeForm: function() { if (!this._form) return; this._form.remove(); this._form = null; this._controls = { }; }, showSaving: function() { this._oldInnerHTML = this.element.innerHTML; this.element.innerHTML = this.options.savingText; this.element.addClassName(this.options.savingClassName); this.element.style.backgroundColor = this._originalBackground; this.element.show(); }, triggerCallback: function(cbName, arg) { if ('function' == typeof this.options[cbName]) { this.options[cbName](this, arg); } }, unregisterListeners: function() { $H(this._listeners).each(function(pair) { if (!this.options.externalControlOnly) this.element.stopObserving(pair.key, pair.value); if (this.options.externalControl) this.options.externalControl.stopObserving(pair.key, pair.value); }.bind(this)); }, wrapUp: function(transport) { this.leaveEditMode(); // Can't use triggerCallback due to backward compatibility: requires // binding + direct element this._boundComplete(transport, this.element); } }); Object.extend(Ajax.InPlaceEditor.prototype, { dispose: Ajax.InPlaceEditor.prototype.destroy }); Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { initialize: function($super, element, url, options) { this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; $super(element, url, options); }, createEditField: function() { var list = document.createElement('select'); list.name = this.options.paramName; list.size = 1; this._controls.editor = list; this._collection = this.options.collection || []; if (this.options.loadCollectionURL) this.loadCollection(); else this.checkForExternalText(); this._form.appendChild(this._controls.editor); }, loadCollection: function() { this._form.addClassName(this.options.loadingClassName); this.showLoadingText(this.options.loadingCollectionText); var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { var js = transport.responseText.strip(); if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check throw('Server returned an invalid collection representation.'); this._collection = eval(js); this.checkForExternalText(); }.bind(this), onFailure: this.onFailure }); new Ajax.Request(this.options.loadCollectionURL, options); }, showLoadingText: function(text) { this._controls.editor.disabled = true; var tempOption = this._controls.editor.firstChild; if (!tempOption) { tempOption = document.createElement('option'); tempOption.value = ''; this._controls.editor.appendChild(tempOption); tempOption.selected = true; } tempOption.update((text || '').stripScripts().stripTags()); }, checkForExternalText: function() { this._text = this.getText(); if (this.options.loadTextURL) this.loadExternalText(); else this.buildOptionList(); }, loadExternalText: function() { this.showLoadingText(this.options.loadingText); var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { this._text = transport.responseText.strip(); this.buildOptionList(); }.bind(this), onFailure: this.onFailure }); new Ajax.Request(this.options.loadTextURL, options); }, buildOptionList: function() { this._form.removeClassName(this.options.loadingClassName); this._collection = this._collection.map(function(entry) { return 2 === entry.length ? entry : [entry, entry].flatten(); }); var marker = ('value' in this.options) ? this.options.value : this._text; var textFound = this._collection.any(function(entry) { return entry[0] == marker; }.bind(this)); this._controls.editor.update(''); var option; this._collection.each(function(entry, index) { option = document.createElement('option'); option.value = entry[0]; option.selected = textFound ? entry[0] == marker : 0 == index; option.appendChild(document.createTextNode(entry[1])); this._controls.editor.appendChild(option); }.bind(this)); this._controls.editor.disabled = false; Field.scrollFreeActivate(this._controls.editor); } }); //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** //**** This only exists for a while, in order to let **** //**** users adapt to the new API. Read up on the new **** //**** API and convert your code to it ASAP! **** Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { if (!options) return; function fallback(name, expr) { if (name in options || expr === undefined) return; options[name] = expr; }; fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : options.cancelLink == options.cancelButton == false ? false : undefined))); fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : options.okLink == options.okButton == false ? false : undefined))); fallback('highlightColor', options.highlightcolor); fallback('highlightEndColor', options.highlightendcolor); }; Object.extend(Ajax.InPlaceEditor, { DefaultOptions: { ajaxOptions: { }, autoRows: 3, // Use when multi-line w/ rows == 1 cancelControl: 'link', // 'link'|'button'|false cancelText: 'cancel', clickToEditText: 'Click to edit', externalControl: null, // id|elt externalControlOnly: false, fieldPostCreation: 'activate', // 'activate'|'focus'|false formClassName: 'inplaceeditor-form', formId: null, // id|elt highlightColor: '#ffff99', highlightEndColor: '#ffffff', hoverClassName: '', htmlResponse: true, loadingClassName: 'inplaceeditor-loading', loadingText: 'Loading...', okControl: 'button', // 'link'|'button'|false okText: 'ok', paramName: 'value', rows: 1, // If 1 and multi-line, uses autoRows savingClassName: 'inplaceeditor-saving', savingText: 'Saving...', size: 0, stripLoadedTextTags: false, submitOnBlur: false, textAfterControls: '', textBeforeControls: '', textBetweenControls: '' }, DefaultCallbacks: { callback: function(form) { return Form.serialize(form); }, onComplete: function(transport, element) { // For backward compatibility, this one is bound to the IPE, and passes // the element directly. It was too often customized, so we don't break it. new Effect.Highlight(element, { startcolor: this.options.highlightColor, keepBackgroundImage: true }); }, onEnterEditMode: null, onEnterHover: function(ipe) { ipe.element.style.backgroundColor = ipe.options.highlightColor; if (ipe._effect) ipe._effect.cancel(); }, onFailure: function(transport, ipe) { alert('Error communication with the server: ' + transport.responseText.stripTags()); }, onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. onLeaveEditMode: null, onLeaveHover: function(ipe) { ipe._effect = new Effect.Highlight(ipe.element, { startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, restorecolor: ipe._originalBackground, keepBackgroundImage: true }); } }, Listeners: { click: 'enterEditMode', keydown: 'checkForEscapeOrReturn', mouseover: 'enterHover', mouseout: 'leaveHover' } }); Ajax.InPlaceCollectionEditor.DefaultOptions = { loadingCollectionText: 'Loading options...' }; // Delayed observer, like Form.Element.Observer, // but waits for delay after last key input // Ideal for live-search fields Form.Element.DelayedObserver = Class.create({ initialize: function(element, delay, callback) { this.delay = delay || 0.5; this.element = $(element); this.callback = callback; this.timer = null; this.lastValue = $F(this.element); Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); }, delayedListener: function(event) { if(this.lastValue == $F(this.element)) return; if(this.timer) clearTimeout(this.timer); this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); this.lastValue = $F(this.element); }, onTimerEvent: function() { this.timer = null; this.callback(this.element, $F(this.element)); } });ruby-openid-2.7.0debian.orig/examples/rails_openid/public/javascripts/effects.js0000644000175000017500000011342312512544714027372 0ustar sbadiasbadia// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // Contributors: // Justin Palmer (http://encytemedia.com/) // Mark Pilgrim (http://diveintomark.org/) // Martin Bialasinki // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ // converts rgb() and #xxx to #xxxxxx format, // returns self (or first argument) if not convertable String.prototype.parseColor = function() { var color = '#'; if (this.slice(0,4) == 'rgb(') { var cols = this.slice(4,this.length-1).split(','); var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); } else { if (this.slice(0,1) == '#') { if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); if (this.length==7) color = this.toLowerCase(); } } return (color.length==7 ? color : (arguments[0] || this)); }; /*--------------------------------------------------------------------------*/ Element.collectTextNodes = function(element) { return $A($(element).childNodes).collect( function(node) { return (node.nodeType==3 ? node.nodeValue : (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); }).flatten().join(''); }; Element.collectTextNodesIgnoreClass = function(element, className) { return $A($(element).childNodes).collect( function(node) { return (node.nodeType==3 ? node.nodeValue : ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? Element.collectTextNodesIgnoreClass(node, className) : '')); }).flatten().join(''); }; Element.setContentZoom = function(element, percent) { element = $(element); element.setStyle({fontSize: (percent/100) + 'em'}); if (Prototype.Browser.WebKit) window.scrollBy(0,0); return element; }; Element.getInlineOpacity = function(element){ return $(element).style.opacity || ''; }; Element.forceRerendering = function(element) { try { element = $(element); var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch(e) { } }; /*--------------------------------------------------------------------------*/ var Effect = { _elementDoesNotExistError: { name: 'ElementDoesNotExistError', message: 'The specified DOM element does not exist, but is required for this effect to operate' }, Transitions: { linear: Prototype.K, sinoidal: function(pos) { return (-Math.cos(pos*Math.PI)/2) + .5; }, reverse: function(pos) { return 1-pos; }, flicker: function(pos) { var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; return pos > 1 ? 1 : pos; }, wobble: function(pos) { return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; }, pulse: function(pos, pulses) { return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; }, spring: function(pos) { return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); }, none: function(pos) { return 0; }, full: function(pos) { return 1; } }, DefaultOptions: { duration: 1.0, // seconds fps: 100, // 100= assume 66fps max. sync: false, // true for combining from: 0.0, to: 1.0, delay: 0.0, queue: 'parallel' }, tagifyText: function(element) { var tagifyStyle = 'position:relative'; if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; element = $(element); $A(element.childNodes).each( function(child) { if (child.nodeType==3) { child.nodeValue.toArray().each( function(character) { element.insertBefore( new Element('span', {style: tagifyStyle}).update( character == ' ' ? String.fromCharCode(160) : character), child); }); Element.remove(child); } }); }, multiple: function(element, effect) { var elements; if (((typeof element == 'object') || Object.isFunction(element)) && (element.length)) elements = element; else elements = $(element).childNodes; var options = Object.extend({ speed: 0.1, delay: 0.0 }, arguments[2] || { }); var masterDelay = options.delay; $A(elements).each( function(element, index) { new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); }); }, PAIRS: { 'slide': ['SlideDown','SlideUp'], 'blind': ['BlindDown','BlindUp'], 'appear': ['Appear','Fade'] }, toggle: function(element, effect) { element = $(element); effect = (effect || 'appear').toLowerCase(); var options = Object.extend({ queue: { position:'end', scope:(element.id || 'global'), limit: 1 } }, arguments[2] || { }); Effect[element.visible() ? Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); } }; Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; /* ------------- core effects ------------- */ Effect.ScopedQueue = Class.create(Enumerable, { initialize: function() { this.effects = []; this.interval = null; }, _each: function(iterator) { this.effects._each(iterator); }, add: function(effect) { var timestamp = new Date().getTime(); var position = Object.isString(effect.options.queue) ? effect.options.queue : effect.options.queue.position; switch(position) { case 'front': // move unstarted effects after this effect this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { e.startOn += effect.finishOn; e.finishOn += effect.finishOn; }); break; case 'with-last': timestamp = this.effects.pluck('startOn').max() || timestamp; break; case 'end': // start effect after last queued effect has finished timestamp = this.effects.pluck('finishOn').max() || timestamp; break; } effect.startOn += timestamp; effect.finishOn += timestamp; if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) this.effects.push(effect); if (!this.interval) this.interval = setInterval(this.loop.bind(this), 15); }, remove: function(effect) { this.effects = this.effects.reject(function(e) { return e==effect }); if (this.effects.length == 0) { clearInterval(this.interval); this.interval = null; } }, loop: function() { var timePos = new Date().getTime(); for(var i=0, len=this.effects.length;i= this.startOn) { if (timePos >= this.finishOn) { this.render(1.0); this.cancel(); this.event('beforeFinish'); if (this.finish) this.finish(); this.event('afterFinish'); return; } var pos = (timePos - this.startOn) / this.totalTime, frame = (pos * this.totalFrames).round(); if (frame > this.currentFrame) { this.render(pos); this.currentFrame = frame; } } }, cancel: function() { if (!this.options.sync) Effect.Queues.get(Object.isString(this.options.queue) ? 'global' : this.options.queue.scope).remove(this); this.state = 'finished'; }, event: function(eventName) { if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); if (this.options[eventName]) this.options[eventName](this); }, inspect: function() { var data = $H(); for(property in this) if (!Object.isFunction(this[property])) data.set(property, this[property]); return '#'; } }); Effect.Parallel = Class.create(Effect.Base, { initialize: function(effects) { this.effects = effects || []; this.start(arguments[1]); }, update: function(position) { this.effects.invoke('render', position); }, finish: function(position) { this.effects.each( function(effect) { effect.render(1.0); effect.cancel(); effect.event('beforeFinish'); if (effect.finish) effect.finish(position); effect.event('afterFinish'); }); } }); Effect.Tween = Class.create(Effect.Base, { initialize: function(object, from, to) { object = Object.isString(object) ? $(object) : object; var args = $A(arguments), method = args.last(), options = args.length == 5 ? args[3] : null; this.method = Object.isFunction(method) ? method.bind(object) : Object.isFunction(object[method]) ? object[method].bind(object) : function(value) { object[method] = value }; this.start(Object.extend({ from: from, to: to }, options || { })); }, update: function(position) { this.method(position); } }); Effect.Event = Class.create(Effect.Base, { initialize: function() { this.start(Object.extend({ duration: 0 }, arguments[0] || { })); }, update: Prototype.emptyFunction }); Effect.Opacity = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); // make this work on IE on elements without 'layout' if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) this.element.setStyle({zoom: 1}); var options = Object.extend({ from: this.element.getOpacity() || 0.0, to: 1.0 }, arguments[1] || { }); this.start(options); }, update: function(position) { this.element.setOpacity(position); } }); Effect.Move = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ x: 0, y: 0, mode: 'relative' }, arguments[1] || { }); this.start(options); }, setup: function() { this.element.makePositioned(); this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); this.originalTop = parseFloat(this.element.getStyle('top') || '0'); if (this.options.mode == 'absolute') { this.options.x = this.options.x - this.originalLeft; this.options.y = this.options.y - this.originalTop; } }, update: function(position) { this.element.setStyle({ left: (this.options.x * position + this.originalLeft).round() + 'px', top: (this.options.y * position + this.originalTop).round() + 'px' }); } }); // for backwards compatibility Effect.MoveBy = function(element, toTop, toLeft) { return new Effect.Move(element, Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); }; Effect.Scale = Class.create(Effect.Base, { initialize: function(element, percent) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ scaleX: true, scaleY: true, scaleContent: true, scaleFromCenter: false, scaleMode: 'box', // 'box' or 'contents' or { } with provided values scaleFrom: 100.0, scaleTo: percent }, arguments[2] || { }); this.start(options); }, setup: function() { this.restoreAfterFinish = this.options.restoreAfterFinish || false; this.elementPositioning = this.element.getStyle('position'); this.originalStyle = { }; ['top','left','width','height','fontSize'].each( function(k) { this.originalStyle[k] = this.element.style[k]; }.bind(this)); this.originalTop = this.element.offsetTop; this.originalLeft = this.element.offsetLeft; var fontSize = this.element.getStyle('font-size') || '100%'; ['em','px','%','pt'].each( function(fontSizeType) { if (fontSize.indexOf(fontSizeType)>0) { this.fontSize = parseFloat(fontSize); this.fontSizeType = fontSizeType; } }.bind(this)); this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; this.dims = null; if (this.options.scaleMode=='box') this.dims = [this.element.offsetHeight, this.element.offsetWidth]; if (/^content/.test(this.options.scaleMode)) this.dims = [this.element.scrollHeight, this.element.scrollWidth]; if (!this.dims) this.dims = [this.options.scaleMode.originalHeight, this.options.scaleMode.originalWidth]; }, update: function(position) { var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); if (this.options.scaleContent && this.fontSize) this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); }, finish: function(position) { if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); }, setDimensions: function(height, width) { var d = { }; if (this.options.scaleX) d.width = width.round() + 'px'; if (this.options.scaleY) d.height = height.round() + 'px'; if (this.options.scaleFromCenter) { var topd = (height - this.dims[0])/2; var leftd = (width - this.dims[1])/2; if (this.elementPositioning == 'absolute') { if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; } else { if (this.options.scaleY) d.top = -topd + 'px'; if (this.options.scaleX) d.left = -leftd + 'px'; } } this.element.setStyle(d); } }); Effect.Highlight = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); this.start(options); }, setup: function() { // Prevent executing on elements not in the layout flow if (this.element.getStyle('display')=='none') { this.cancel(); return; } // Disable background image during the effect this.oldStyle = { }; if (!this.options.keepBackgroundImage) { this.oldStyle.backgroundImage = this.element.getStyle('background-image'); this.element.setStyle({backgroundImage: 'none'}); } if (!this.options.endcolor) this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); if (!this.options.restorecolor) this.options.restorecolor = this.element.getStyle('background-color'); // init color calculations this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); }, update: function(position) { this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); }, finish: function() { this.element.setStyle(Object.extend(this.oldStyle, { backgroundColor: this.options.restorecolor })); } }); Effect.ScrollTo = function(element) { var options = arguments[1] || { }, scrollOffsets = document.viewport.getScrollOffsets(), elementOffsets = $(element).cumulativeOffset(); if (options.offset) elementOffsets[1] += options.offset; return new Effect.Tween(null, scrollOffsets.top, elementOffsets[1], options, function(p){ scrollTo(scrollOffsets.left, p.round()); } ); }; /* ------------- combination effects ------------- */ Effect.Fade = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); var options = Object.extend({ from: element.getOpacity() || 1.0, to: 0.0, afterFinishInternal: function(effect) { if (effect.options.to!=0) return; effect.element.hide().setStyle({opacity: oldOpacity}); } }, arguments[1] || { }); return new Effect.Opacity(element,options); }; Effect.Appear = function(element) { element = $(element); var options = Object.extend({ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), to: 1.0, // force Safari to render floated elements properly afterFinishInternal: function(effect) { effect.element.forceRerendering(); }, beforeSetup: function(effect) { effect.element.setOpacity(effect.options.from).show(); }}, arguments[1] || { }); return new Effect.Opacity(element,options); }; Effect.Puff = function(element) { element = $(element); var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position'), top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; return new Effect.Parallel( [ new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], Object.extend({ duration: 1.0, beforeSetupInternal: function(effect) { Position.absolutize(effect.effects[0].element); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().setStyle(oldStyle); } }, arguments[1] || { }) ); }; Effect.BlindUp = function(element) { element = $(element); element.makeClipping(); return new Effect.Scale(element, 0, Object.extend({ scaleContent: false, scaleX: false, restoreAfterFinish: true, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }, arguments[1] || { }) ); }; Effect.BlindDown = function(element) { element = $(element); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.element.undoClipping(); } }, arguments[1] || { })); }; Effect.SwitchOff = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); return new Effect.Appear(element, Object.extend({ duration: 0.4, from: 0, transition: Effect.Transitions.flicker, afterFinishInternal: function(effect) { new Effect.Scale(effect.element, 1, { duration: 0.3, scaleFromCenter: true, scaleX: false, scaleContent: false, restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); } }); } }, arguments[1] || { })); }; Effect.DropOut = function(element) { element = $(element); var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left'), opacity: element.getInlineOpacity() }; return new Effect.Parallel( [ new Effect.Move(element, {x: 0, y: 100, sync: true }), new Effect.Opacity(element, { sync: true, to: 0.0 }) ], Object.extend( { duration: 0.5, beforeSetup: function(effect) { effect.effects[0].element.makePositioned(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); } }, arguments[1] || { })); }; Effect.Shake = function(element) { element = $(element); var options = Object.extend({ distance: 20, duration: 0.5 }, arguments[1] || {}); var distance = parseFloat(options.distance); var split = parseFloat(options.duration) / 10.0; var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left') }; return new Effect.Move(element, { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { effect.element.undoPositioned().setStyle(oldStyle); }}); }}); }}); }}); }}); }}); }; Effect.SlideDown = function(element) { element = $(element).cleanWhitespace(); // SlideDown need to have the content of the element wrapped in a container element with fixed height! var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: window.opera ? 0 : 1, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if (window.opera) effect.element.setStyle({top: ''}); effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({bottom: (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, afterFinishInternal: function(effect) { effect.element.undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } }, arguments[1] || { }) ); }; Effect.SlideUp = function(element) { element = $(element).cleanWhitespace(); var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, window.opera ? 0 : 1, Object.extend({ scaleContent: false, scaleX: false, scaleMode: 'box', scaleFrom: 100, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if (window.opera) effect.element.setStyle({top: ''}); effect.element.makeClipping().show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({bottom: (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } }, arguments[1] || { }) ); }; // Bug in opera makes the TD containing this element expand for a instance after finish Effect.Squish = function(element) { return new Effect.Scale(element, window.opera ? 1 : 0, { restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }); }; Effect.Grow = function(element) { element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.full }, arguments[1] || { }); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var initialMoveX, initialMoveY; var moveX, moveY; switch (options.direction) { case 'top-left': initialMoveX = initialMoveY = moveX = moveY = 0; break; case 'top-right': initialMoveX = dims.width; initialMoveY = moveY = 0; moveX = -dims.width; break; case 'bottom-left': initialMoveX = moveX = 0; initialMoveY = dims.height; moveY = -dims.height; break; case 'bottom-right': initialMoveX = dims.width; initialMoveY = dims.height; moveX = -dims.width; moveY = -dims.height; break; case 'center': initialMoveX = dims.width / 2; initialMoveY = dims.height / 2; moveX = -dims.width / 2; moveY = -dims.height / 2; break; } return new Effect.Move(element, { x: initialMoveX, y: initialMoveY, duration: 0.01, beforeSetup: function(effect) { effect.element.hide().makeClipping().makePositioned(); }, afterFinishInternal: function(effect) { new Effect.Parallel( [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), new Effect.Scale(effect.element, 100, { scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) ], Object.extend({ beforeSetup: function(effect) { effect.effects[0].element.setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); } }, options) ); } }); }; Effect.Shrink = function(element) { element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.none }, arguments[1] || { }); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var moveX, moveY; switch (options.direction) { case 'top-left': moveX = moveY = 0; break; case 'top-right': moveX = dims.width; moveY = 0; break; case 'bottom-left': moveX = 0; moveY = dims.height; break; case 'bottom-right': moveX = dims.width; moveY = dims.height; break; case 'center': moveX = dims.width / 2; moveY = dims.height / 2; break; } return new Effect.Parallel( [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) ], Object.extend({ beforeStartInternal: function(effect) { effect.effects[0].element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } }, options) ); }; Effect.Pulsate = function(element) { element = $(element); var options = arguments[1] || { }, oldOpacity = element.getInlineOpacity(), transition = options.transition || Effect.Transitions.linear, reverser = function(pos){ return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); }; return new Effect.Opacity(element, Object.extend(Object.extend({ duration: 2.0, from: 0, afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } }, options), {transition: reverser})); }; Effect.Fold = function(element) { element = $(element); var oldStyle = { top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; element.makeClipping(); return new Effect.Scale(element, 5, Object.extend({ scaleContent: false, scaleX: false, afterFinishInternal: function(effect) { new Effect.Scale(element, 1, { scaleContent: false, scaleY: false, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().setStyle(oldStyle); } }); }}, arguments[1] || { })); }; Effect.Morph = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ style: { } }, arguments[1] || { }); if (!Object.isString(options.style)) this.style = $H(options.style); else { if (options.style.include(':')) this.style = options.style.parseStyle(); else { this.element.addClassName(options.style); this.style = $H(this.element.getStyles()); this.element.removeClassName(options.style); var css = this.element.getStyles(); this.style = this.style.reject(function(style) { return style.value == css[style.key]; }); options.afterFinishInternal = function(effect) { effect.element.addClassName(effect.options.style); effect.transforms.each(function(transform) { effect.element.style[transform.style] = ''; }); }; } } this.start(options); }, setup: function(){ function parseColor(color){ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; color = color.parseColor(); return $R(0,2).map(function(i){ return parseInt( color.slice(i*2+1,i*2+3), 16 ); }); } this.transforms = this.style.map(function(pair){ var property = pair[0], value = pair[1], unit = null; if (value.parseColor('#zzzzzz') != '#zzzzzz') { value = value.parseColor(); unit = 'color'; } else if (property == 'opacity') { value = parseFloat(value); if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) this.element.setStyle({zoom: 1}); } else if (Element.CSS_LENGTH.test(value)) { var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); value = parseFloat(components[1]); unit = (components.length == 3) ? components[2] : null; } var originalValue = this.element.getStyle(property); return { style: property.camelize(), originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), targetValue: unit=='color' ? parseColor(value) : value, unit: unit }; }.bind(this)).reject(function(transform){ return ( (transform.originalValue == transform.targetValue) || ( transform.unit != 'color' && (isNaN(transform.originalValue) || isNaN(transform.targetValue)) ) ); }); }, update: function(position) { var style = { }, transform, i = this.transforms.length; while(i--) style[(transform = this.transforms[i]).style] = transform.unit=='color' ? '#'+ (Math.round(transform.originalValue[0]+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + (Math.round(transform.originalValue[1]+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + (Math.round(transform.originalValue[2]+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : (transform.originalValue + (transform.targetValue - transform.originalValue) * position).toFixed(3) + (transform.unit === null ? '' : transform.unit); this.element.setStyle(style, true); } }); Effect.Transform = Class.create({ initialize: function(tracks){ this.tracks = []; this.options = arguments[1] || { }; this.addTracks(tracks); }, addTracks: function(tracks){ tracks.each(function(track){ track = $H(track); var data = track.values().first(); this.tracks.push($H({ ids: track.keys().first(), effect: Effect.Morph, options: { style: data } })); }.bind(this)); return this; }, play: function(){ return new Effect.Parallel( this.tracks.map(function(track){ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); var elements = [$(ids) || $$(ids)].flatten(); return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); }).flatten(), this.options ); } }); Element.CSS_PROPERTIES = $w( 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + 'fontSize fontWeight height left letterSpacing lineHeight ' + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + 'right textIndent top width wordSpacing zIndex'); Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; String.__parseStyleElement = document.createElement('div'); String.prototype.parseStyle = function(){ var style, styleRules = $H(); if (Prototype.Browser.WebKit) style = new Element('div',{style:this}).style; else { String.__parseStyleElement.innerHTML = '
    '; style = String.__parseStyleElement.childNodes[0].style; } Element.CSS_PROPERTIES.each(function(property){ if (style[property]) styleRules.set(property, style[property]); }); if (Prototype.Browser.IE && this.include('opacity')) styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); return styleRules; }; if (document.defaultView && document.defaultView.getComputedStyle) { Element.getStyles = function(element) { var css = document.defaultView.getComputedStyle($(element), null); return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { styles[property] = css[property]; return styles; }); }; } else { Element.getStyles = function(element) { element = $(element); var css = element.currentStyle, styles; styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { results[property] = css[property]; return results; }); if (!styles.opacity) styles.opacity = element.getOpacity(); return styles; }; } Effect.Methods = { morph: function(element, style) { element = $(element); new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); return element; }, visualEffect: function(element, effect, options) { element = $(element); var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); new Effect[klass](element, options); return element; }, highlight: function(element, options) { element = $(element); new Effect.Highlight(element, options); return element; } }; $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ 'pulsate shake puff squish switchOff dropOut').each( function(effect) { Effect.Methods[effect] = function(element, options){ element = $(element); Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); return element; }; } ); $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( function(f) { Effect.Methods[f] = Element[f]; } ); Element.addMethods(Effect.Methods);ruby-openid-2.7.0debian.orig/examples/rails_openid/public/javascripts/prototype.js0000644000175000017500000037531212512544714030027 0ustar sbadiasbadia/* Prototype JavaScript framework, version 1.6.0.3 * (c) 2005-2008 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. * For details, see the Prototype web site: http://www.prototypejs.org/ * *--------------------------------------------------------------------------*/ var Prototype = { Version: '1.6.0.3', Browser: { IE: !!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1), Opera: navigator.userAgent.indexOf('Opera') > -1, WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') === -1, MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) }, BrowserFeatures: { XPath: !!document.evaluate, SelectorsAPI: !!document.querySelector, ElementExtensions: !!window.HTMLElement, SpecificElementExtensions: document.createElement('div')['__proto__'] && document.createElement('div')['__proto__'] !== document.createElement('form')['__proto__'] }, ScriptFragment: ']*>([\\S\\s]*?)<\/script>', JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } }; if (Prototype.Browser.MobileSafari) Prototype.BrowserFeatures.SpecificElementExtensions = false; /* Based on Alex Arnell's inheritance implementation. */ var Class = { create: function() { var parent = null, properties = $A(arguments); if (Object.isFunction(properties[0])) parent = properties.shift(); function klass() { this.initialize.apply(this, arguments); } Object.extend(klass, Class.Methods); klass.superclass = parent; klass.subclasses = []; if (parent) { var subclass = function() { }; subclass.prototype = parent.prototype; klass.prototype = new subclass; parent.subclasses.push(klass); } for (var i = 0; i < properties.length; i++) klass.addMethods(properties[i]); if (!klass.prototype.initialize) klass.prototype.initialize = Prototype.emptyFunction; klass.prototype.constructor = klass; return klass; } }; Class.Methods = { addMethods: function(source) { var ancestor = this.superclass && this.superclass.prototype; var properties = Object.keys(source); if (!Object.keys({ toString: true }).length) properties.push("toString", "valueOf"); for (var i = 0, length = properties.length; i < length; i++) { var property = properties[i], value = source[property]; if (ancestor && Object.isFunction(value) && value.argumentNames().first() == "$super") { var method = value; value = (function(m) { return function() { return ancestor[m].apply(this, arguments) }; })(property).wrap(method); value.valueOf = method.valueOf.bind(method); value.toString = method.toString.bind(method); } this.prototype[property] = value; } return this; } }; var Abstract = { }; Object.extend = function(destination, source) { for (var property in source) destination[property] = source[property]; return destination; }; Object.extend(Object, { inspect: function(object) { try { if (Object.isUndefined(object)) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : String(object); } catch (e) { if (e instanceof RangeError) return '...'; throw e; } }, toJSON: function(object) { var type = typeof object; switch (type) { case 'undefined': case 'function': case 'unknown': return; case 'boolean': return object.toString(); } if (object === null) return 'null'; if (object.toJSON) return object.toJSON(); if (Object.isElement(object)) return; var results = []; for (var property in object) { var value = Object.toJSON(object[property]); if (!Object.isUndefined(value)) results.push(property.toJSON() + ': ' + value); } return '{' + results.join(', ') + '}'; }, toQueryString: function(object) { return $H(object).toQueryString(); }, toHTML: function(object) { return object && object.toHTML ? object.toHTML() : String.interpret(object); }, keys: function(object) { var keys = []; for (var property in object) keys.push(property); return keys; }, values: function(object) { var values = []; for (var property in object) values.push(object[property]); return values; }, clone: function(object) { return Object.extend({ }, object); }, isElement: function(object) { return !!(object && object.nodeType == 1); }, isArray: function(object) { return object != null && typeof object == "object" && 'splice' in object && 'join' in object; }, isHash: function(object) { return object instanceof Hash; }, isFunction: function(object) { return typeof object == "function"; }, isString: function(object) { return typeof object == "string"; }, isNumber: function(object) { return typeof object == "number"; }, isUndefined: function(object) { return typeof object == "undefined"; } }); Object.extend(Function.prototype, { argumentNames: function() { var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] .replace(/\s+/g, '').split(','); return names.length == 1 && !names[0] ? [] : names; }, bind: function() { if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } }, bindAsEventListener: function() { var __method = this, args = $A(arguments), object = args.shift(); return function(event) { return __method.apply(object, [event || window.event].concat(args)); } }, curry: function() { if (!arguments.length) return this; var __method = this, args = $A(arguments); return function() { return __method.apply(this, args.concat($A(arguments))); } }, delay: function() { var __method = this, args = $A(arguments), timeout = args.shift() * 1000; return window.setTimeout(function() { return __method.apply(__method, args); }, timeout); }, defer: function() { var args = [0.01].concat($A(arguments)); return this.delay.apply(this, args); }, wrap: function(wrapper) { var __method = this; return function() { return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); } }, methodize: function() { if (this._methodized) return this._methodized; var __method = this; return this._methodized = function() { return __method.apply(null, [this].concat($A(arguments))); }; } }); Date.prototype.toJSON = function() { return '"' + this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + this.getUTCDate().toPaddedString(2) + 'T' + this.getUTCHours().toPaddedString(2) + ':' + this.getUTCMinutes().toPaddedString(2) + ':' + this.getUTCSeconds().toPaddedString(2) + 'Z"'; }; var Try = { these: function() { var returnValue; for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) { } } return returnValue; } }; RegExp.prototype.match = RegExp.prototype.test; RegExp.escape = function(str) { return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }; /*--------------------------------------------------------------------------*/ var PeriodicalExecuter = Class.create({ initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; this.currentlyExecuting = false; this.registerCallback(); }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, execute: function() { this.callback(this); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.execute(); } finally { this.currentlyExecuting = false; } } } }); Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); Object.extend(String.prototype, { gsub: function(pattern, replacement) { var result = '', source = this, match; replacement = arguments.callee.prepareReplacement(replacement); while (source.length > 0) { if (match = source.match(pattern)) { result += source.slice(0, match.index); result += String.interpret(replacement(match)); source = source.slice(match.index + match[0].length); } else { result += source, source = ''; } } return result; }, sub: function(pattern, replacement, count) { replacement = this.gsub.prepareReplacement(replacement); count = Object.isUndefined(count) ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); }, scan: function(pattern, iterator) { this.gsub(pattern, iterator); return String(this); }, truncate: function(length, truncation) { length = length || 30; truncation = Object.isUndefined(truncation) ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation : String(this); }, strip: function() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); }, stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, stripScripts: function() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); }, extractScripts: function() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); }, evalScripts: function() { return this.extractScripts().map(function(script) { return eval(script) }); }, escapeHTML: function() { var self = arguments.callee; self.text.data = this; return self.div.innerHTML; }, unescapeHTML: function() { var div = new Element('div'); div.innerHTML = this.stripTags(); return div.childNodes[0] ? (div.childNodes.length > 1 ? $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : div.childNodes[0].nodeValue) : ''; }, toQueryParams: function(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); if (!match) return { }; return match[1].split(separator || '&').inject({ }, function(hash, pair) { if ((pair = pair.split('='))[0]) { var key = decodeURIComponent(pair.shift()); var value = pair.length > 1 ? pair.join('=') : pair[0]; if (value != undefined) value = decodeURIComponent(value); if (key in hash) { if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; } return hash; }); }, toArray: function() { return this.split(''); }, succ: function() { return this.slice(0, this.length - 1) + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); }, times: function(count) { return count < 1 ? '' : new Array(count + 1).join(this); }, camelize: function() { var parts = this.split('-'), len = parts.length; if (len == 1) return parts[0]; var camelized = this.charAt(0) == '-' ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) : parts[0]; for (var i = 1; i < len; i++) camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); return camelized; }, capitalize: function() { return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); }, underscore: function() { return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); }, dasherize: function() { return this.gsub(/_/,'-'); }, inspect: function(useDoubleQuotes) { var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { var character = String.specialChar[match[0]]; return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; return "'" + escapedString.replace(/'/g, '\\\'') + "'"; }, toJSON: function() { return this.inspect(true); }, unfilterJSON: function(filter) { return this.sub(filter || Prototype.JSONFilter, '#{1}'); }, isJSON: function() { var str = this; if (str.blank()) return false; str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); }, evalJSON: function(sanitize) { var json = this.unfilterJSON(); try { if (!sanitize || json.isJSON()) return eval('(' + json + ')'); } catch (e) { } throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); }, include: function(pattern) { return this.indexOf(pattern) > -1; }, startsWith: function(pattern) { return this.indexOf(pattern) === 0; }, endsWith: function(pattern) { var d = this.length - pattern.length; return d >= 0 && this.lastIndexOf(pattern) === d; }, empty: function() { return this == ''; }, blank: function() { return /^\s*$/.test(this); }, interpolate: function(object, pattern) { return new Template(this, pattern).evaluate(object); } }); if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { escapeHTML: function() { return this.replace(/&/g,'&').replace(//g,'>'); }, unescapeHTML: function() { return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } }); String.prototype.gsub.prepareReplacement = function(replacement) { if (Object.isFunction(replacement)) return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; }; String.prototype.parseQuery = String.prototype.toQueryParams; Object.extend(String.prototype.escapeHTML, { div: document.createElement('div'), text: document.createTextNode('') }); String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); var Template = Class.create({ initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { if (Object.isFunction(object.toTemplateReplacements)) object = object.toTemplateReplacements(); return this.template.gsub(this.pattern, function(match) { if (object == null) return ''; var before = match[1] || ''; if (before == '\\') return match[2]; var ctx = object, expr = match[3]; var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; match = pattern.exec(expr); if (match == null) return before; while (match != null) { var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; ctx = ctx[comp]; if (null == ctx || '' == match[3]) break; expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); match = pattern.exec(expr); } return before + String.interpret(ctx); }); } }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = { }; var Enumerable = { each: function(iterator, context) { var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; } return this; }, eachSlice: function(number, iterator, context) { var index = -number, slices = [], array = this.toArray(); if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); }, all: function(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; }, any: function(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator.call(context, value, index)) throw $break; }); return result; }, collect: function(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; }, detect: function(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; }, findAll: function(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; }, grep: function(filter, iterator, context) { iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(filter); this.each(function(value, index) { if (filter.match(value)) results.push(iterator.call(context, value, index)); }); return results; }, include: function(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true; var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; }, inGroupsOf: function(number, fillWith) { fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); }, inject: function(memo, iterator, context) { this.each(function(value, index) { memo = iterator.call(context, memo, value, index); }); return memo; }, invoke: function(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); }, max: function(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); return result; }, min: function(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); return result; }, partition: function(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator.call(context, value, index) ? trues : falses).push(value); }); return [trues, falses]; }, pluck: function(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; }, reject: function(iterator, context) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; }, sortBy: function(iterator, context) { return this.map(function(value, index) { return { value: value, criteria: iterator.call(context, value, index) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); }, toArray: function() { return this.map(); }, zip: function() { var iterator = Prototype.K, args = $A(arguments); if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); }, size: function() { return this.toArray().length; }, inspect: function() { return '#'; } }; Object.extend(Enumerable, { map: Enumerable.collect, find: Enumerable.detect, select: Enumerable.findAll, filter: Enumerable.findAll, member: Enumerable.include, entries: Enumerable.toArray, every: Enumerable.all, some: Enumerable.any }); function $A(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; } if (Prototype.Browser.WebKit) { $A = function(iterable) { if (!iterable) return []; // In Safari, only use the `toArray` method if it's not a NodeList. // A NodeList is a function, has an function `item` property, and a numeric // `length` property. Adapted from Google Doctype. if (!(typeof iterable === 'function' && typeof iterable.length === 'number' && typeof iterable.item === 'function') && iterable.toArray) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; }; } Array.from = $A; Object.extend(Array.prototype, Enumerable); if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; Object.extend(Array.prototype, { _each: function(iterator) { for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); }, clear: function() { this.length = 0; return this; }, first: function() { return this[0]; }, last: function() { return this[this.length - 1]; }, compact: function() { return this.select(function(value) { return value != null; }); }, flatten: function() { return this.inject([], function(array, value) { return array.concat(Object.isArray(value) ? value.flatten() : [value]); }); }, without: function() { var values = $A(arguments); return this.select(function(value) { return !values.include(value); }); }, reverse: function(inline) { return (inline !== false ? this : this.toArray())._reverse(); }, reduce: function() { return this.length > 1 ? this : this[0]; }, uniq: function(sorted) { return this.inject([], function(array, value, index) { if (0 == index || (sorted ? array.last() != value : !array.include(value))) array.push(value); return array; }); }, intersect: function(array) { return this.uniq().findAll(function(item) { return array.detect(function(value) { return item === value }); }); }, clone: function() { return [].concat(this); }, size: function() { return this.length; }, inspect: function() { return '[' + this.map(Object.inspect).join(', ') + ']'; }, toJSON: function() { var results = []; this.each(function(object) { var value = Object.toJSON(object); if (!Object.isUndefined(value)) results.push(value); }); return '[' + results.join(', ') + ']'; } }); // use native browser JS 1.6 implementation if available if (Object.isFunction(Array.prototype.forEach)) Array.prototype._each = Array.prototype.forEach; if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { i || (i = 0); var length = this.length; if (i < 0) i = length + i; for (; i < length; i++) if (this[i] === item) return i; return -1; }; if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; var n = this.slice(0, i).reverse().indexOf(item); return (n < 0) ? n : i - n - 1; }; Array.prototype.toArray = Array.prototype.clone; function $w(string) { if (!Object.isString(string)) return []; string = string.strip(); return string ? string.split(/\s+/) : []; } if (Prototype.Browser.Opera){ Array.prototype.concat = function() { var array = []; for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); for (var i = 0, length = arguments.length; i < length; i++) { if (Object.isArray(arguments[i])) { for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) array.push(arguments[i][j]); } else { array.push(arguments[i]); } } return array; }; } Object.extend(Number.prototype, { toColorPart: function() { return this.toPaddedString(2, 16); }, succ: function() { return this + 1; }, times: function(iterator, context) { $R(0, this, true).each(iterator, context); return this; }, toPaddedString: function(length, radix) { var string = this.toString(radix || 10); return '0'.times(length - string.length) + string; }, toJSON: function() { return isFinite(this) ? this.toString() : 'null'; } }); $w('abs round ceil floor').each(function(method){ Number.prototype[method] = Math[method].methodize(); }); function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function() { function toQueryPair(key, value) { if (Object.isUndefined(value)) return key; return key + '=' + encodeURIComponent(String.interpret(value)); } return { initialize: function(object) { this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); }, _each: function(iterator) { for (var key in this._object) { var value = this._object[key], pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }, set: function(key, value) { return this._object[key] = value; }, get: function(key) { // simulating poorly supported hasOwnProperty if (this._object[key] !== Object.prototype[key]) return this._object[key]; }, unset: function(key) { var value = this._object[key]; delete this._object[key]; return value; }, toObject: function() { return Object.clone(this._object); }, keys: function() { return this.pluck('key'); }, values: function() { return this.pluck('value'); }, index: function(value) { var match = this.detect(function(pair) { return pair.value === value; }); return match && match.key; }, merge: function(object) { return this.clone().update(object); }, update: function(object) { return new Hash(object).inject(this, function(result, pair) { result.set(pair.key, pair.value); return result; }); }, toQueryString: function() { return this.inject([], function(results, pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) return results.concat(values.map(toQueryPair.curry(key))); } else results.push(toQueryPair(key, values)); return results; }).join('&'); }, inspect: function() { return '#'; }, toJSON: function() { return Object.toJSON(this.toObject()); }, clone: function() { return new Hash(this); } } })()); Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; Hash.from = $H; var ObjectRange = Class.create(Enumerable, { initialize: function(start, end, exclusive) { this.start = start; this.end = end; this.exclusive = exclusive; }, _each: function(iterator) { var value = this.start; while (this.include(value)) { iterator(value); value = value.succ(); } }, include: function(value) { if (value < this.start) return false; if (this.exclusive) return value < this.end; return value <= this.end; } }); var $R = function(start, end, exclusive) { return new ObjectRange(start, end, exclusive); }; var Ajax = { getTransport: function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; }, activeRequestCount: 0 }; Ajax.Responders = { responders: [], _each: function(iterator) { this.responders._each(iterator); }, register: function(responder) { if (!this.include(responder)) this.responders.push(responder); }, unregister: function(responder) { this.responders = this.responders.without(responder); }, dispatch: function(callback, request, transport, json) { this.each(function(responder) { if (Object.isFunction(responder[callback])) { try { responder[callback].apply(responder, [request, transport, json]); } catch (e) { } } }); } }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++ }, onComplete: function() { Ajax.activeRequestCount-- } }); Ajax.Base = Class.create({ initialize: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '', evalJSON: true, evalJS: true }; Object.extend(this.options, options || { }); this.options.method = this.options.method.toLowerCase(); if (Object.isString(this.options.parameters)) this.options.parameters = this.options.parameters.toQueryParams(); else if (Object.isHash(this.options.parameters)) this.options.parameters = this.options.parameters.toObject(); } }); Ajax.Request = Class.create(Ajax.Base, { _complete: false, initialize: function($super, url, options) { $super(options); this.transport = Ajax.getTransport(); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { // simulate other verbs over post params['_method'] = this.method; this.method = 'post'; } this.parameters = params; if (params = Object.toQueryString(params)) { // when GET, append parameters to URL if (this.method == 'get') this.url += (this.url.include('?') ? '&' : '?') + params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='; } try { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); } catch (e) { this.dispatchException(e); } }, onStateChange: function() { var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete)) this.respondToReadyState(this.transport.readyState); }, setRequestHeaders: function() { var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post') { headers['Content-type'] = this.options.contentType + (this.options.encoding ? '; charset=' + this.options.encoding : ''); /* Force "Connection: close" for older Mozilla browsers to work * around a bug where XMLHttpRequest sends an incorrect * Content-length header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) headers['Connection'] = 'close'; } // user-defined headers if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; if (Object.isFunction(extras.push)) for (var i = 0, length = extras.length; i < length; i += 2) headers[extras[i]] = extras[i+1]; else $H(extras).each(function(pair) { headers[pair.key] = pair.value }); } for (var name in headers) this.transport.setRequestHeader(name, headers[name]); }, success: function() { var status = this.getStatus(); return !status || (status >= 200 && status < 300); }, getStatus: function() { try { return this.transport.status || 0; } catch (e) { return 0 } }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); if (state == 'Complete') { try { this._complete = true; (this.options['on' + response.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(response, response.headerJSON); } catch (e) { this.dispatchException(e); } var contentType = response.getHeader('Content-type'); if (this.options.evalJS == 'force' || (this.options.evalJS && this.isSameOrigin() && contentType && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) this.evalResponse(); } try { (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { // avoid memory leak in MSIE: clean up this.transport.onreadystatechange = Prototype.emptyFunction; } }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, getHeader: function(name) { try { return this.transport.getResponseHeader(name) || null; } catch (e) { return null } }, evalResponse: function() { try { return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } }, dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Response = Class.create({ initialize: function(request){ this.request = request; var transport = this.transport = request.transport, readyState = this.readyState = transport.readyState; if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { this.status = this.getStatus(); this.statusText = this.getStatusText(); this.responseText = String.interpret(transport.responseText); this.headerJSON = this._getHeaderJSON(); } if(readyState == 4) { var xml = transport.responseXML; this.responseXML = Object.isUndefined(xml) ? null : xml; this.responseJSON = this._getResponseJSON(); } }, status: 0, statusText: '', getStatus: Ajax.Request.prototype.getStatus, getStatusText: function() { try { return this.transport.statusText || ''; } catch (e) { return '' } }, getHeader: Ajax.Request.prototype.getHeader, getAllHeaders: function() { try { return this.getAllResponseHeaders(); } catch (e) { return null } }, getResponseHeader: function(name) { return this.transport.getResponseHeader(name); }, getAllResponseHeaders: function() { return this.transport.getAllResponseHeaders(); }, _getHeaderJSON: function() { var json = this.getHeader('X-JSON'); if (!json) return null; json = decodeURIComponent(escape(json)); try { return json.evalJSON(this.request.options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } }, _getResponseJSON: function() { var options = this.request.options; if (!options.evalJSON || (options.evalJSON != 'force' && !(this.getHeader('Content-type') || '').include('application/json')) || this.responseText.blank()) return null; try { return this.responseText.evalJSON(options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } } }); Ajax.Updater = Class.create(Ajax.Request, { initialize: function($super, container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) }; options = Object.clone(options); var onComplete = options.onComplete; options.onComplete = (function(response, json) { this.updateContent(response.responseText); if (Object.isFunction(onComplete)) onComplete(response, json); }).bind(this); $super(url, options); }, updateContent: function(responseText) { var receiver = this.container[this.success() ? 'success' : 'failure'], options = this.options; if (!options.evalScripts) responseText = responseText.stripScripts(); if (receiver = $(receiver)) { if (options.insertion) { if (Object.isString(options.insertion)) { var insertion = { }; insertion[options.insertion] = responseText; receiver.insert(insertion); } else options.insertion(receiver, responseText); } else receiver.update(responseText); } } }); Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { initialize: function($super, container, url, options) { $super(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); this.updater = { }; this.container = container; this.url = url; this.start(); }, start: function() { this.options.onComplete = this.updateComplete.bind(this); this.onTimerEvent(); }, stop: function() { this.updater.options.onComplete = undefined; clearTimeout(this.timer); (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(response) { if (this.options.decay) { this.decay = (response.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = response.responseText; } this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (Object.isString(element)) element = document.getElementById(element); return Element.extend(element); } if (Prototype.BrowserFeatures.XPath) { document._getElementsByXPath = function(expression, parentElement) { var results = []; var query = document.evaluate(expression, $(parentElement) || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0, length = query.snapshotLength; i < length; i++) results.push(Element.extend(query.snapshotItem(i))); return results; }; } /*--------------------------------------------------------------------------*/ if (!window.Node) var Node = { }; if (!Node.ELEMENT_NODE) { // DOM level 2 ECMAScript Language Binding Object.extend(Node, { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12 }); } (function() { var element = this.Element; this.Element = function(tagName, attributes) { attributes = attributes || { }; tagName = tagName.toLowerCase(); var cache = Element.cache; if (Prototype.Browser.IE && attributes.name) { tagName = '<' + tagName + ' name="' + attributes.name + '">'; delete attributes.name; return Element.writeAttribute(document.createElement(tagName), attributes); } if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); }; Object.extend(this.Element, element || { }); if (element) this.Element.prototype = element.prototype; }).call(window); Element.cache = { }; Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, toggle: function(element) { element = $(element); Element[Element.visible(element) ? 'hide' : 'show'](element); return element; }, hide: function(element) { element = $(element); element.style.display = 'none'; return element; }, show: function(element) { element = $(element); element.style.display = ''; return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); return element; }, update: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); element.innerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }, replace: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); else if (!Object.isElement(content)) { content = Object.toHTML(content); var range = element.ownerDocument.createRange(); range.selectNode(element); content.evalScripts.bind(content).defer(); content = range.createContextualFragment(content.stripScripts()); } element.parentNode.replaceChild(content, element); return element; }, insert: function(element, insertions) { element = $(element); if (Object.isString(insertions) || Object.isNumber(insertions) || Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) insertions = {bottom:insertions}; var content, insert, tagName, childNodes; for (var position in insertions) { content = insertions[position]; position = position.toLowerCase(); insert = Element._insertionTranslations[position]; if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { insert(element, content); continue; } content = Object.toHTML(content); tagName = ((position == 'before' || position == 'after') ? element.parentNode : element).tagName.toUpperCase(); childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); if (position == 'top' || position == 'after') childNodes.reverse(); childNodes.each(insert.curry(element)); content.evalScripts.bind(content).defer(); } return element; }, wrap: function(element, wrapper, attributes) { element = $(element); if (Object.isElement(wrapper)) $(wrapper).writeAttribute(attributes || { }); else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); else wrapper = new Element('div', wrapper); if (element.parentNode) element.parentNode.replaceChild(wrapper, element); wrapper.appendChild(element); return wrapper; }, inspect: function(element) { element = $(element); var result = '<' + element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { var property = pair.first(), attribute = pair.last(); var value = (element[property] || '').toString(); if (value) result += ' ' + attribute + '=' + value.inspect(true); }); return result + '>'; }, recursivelyCollect: function(element, property) { element = $(element); var elements = []; while (element = element[property]) if (element.nodeType == 1) elements.push(Element.extend(element)); return elements; }, ancestors: function(element) { return $(element).recursivelyCollect('parentNode'); }, descendants: function(element) { return $(element).select("*"); }, firstDescendant: function(element) { element = $(element).firstChild; while (element && element.nodeType != 1) element = element.nextSibling; return $(element); }, immediateDescendants: function(element) { if (!(element = $(element).firstChild)) return []; while (element && element.nodeType != 1) element = element.nextSibling; if (element) return [element].concat($(element).nextSiblings()); return []; }, previousSiblings: function(element) { return $(element).recursivelyCollect('previousSibling'); }, nextSiblings: function(element) { return $(element).recursivelyCollect('nextSibling'); }, siblings: function(element) { element = $(element); return element.previousSiblings().reverse().concat(element.nextSiblings()); }, match: function(element, selector) { if (Object.isString(selector)) selector = new Selector(selector); return selector.match($(element)); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); var ancestors = element.ancestors(); return Object.isNumber(expression) ? ancestors[expression] : Selector.findElement(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? element.descendants()[expression] : Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); var previousSiblings = element.previousSiblings(); return Object.isNumber(expression) ? previousSiblings[expression] : Selector.findElement(previousSiblings, expression, index); }, next: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); var nextSiblings = element.nextSiblings(); return Object.isNumber(expression) ? nextSiblings[expression] : Selector.findElement(nextSiblings, expression, index); }, select: function() { var args = $A(arguments), element = $(args.shift()); return Selector.findChildElements(element, args); }, adjacent: function() { var args = $A(arguments), element = $(args.shift()); return Selector.findChildElements(element.parentNode, args).without(element); }, identify: function(element) { element = $(element); var id = element.readAttribute('id'), self = arguments.callee; if (id) return id; do { id = 'anonymous_element_' + self.counter++ } while ($(id)); element.writeAttribute('id', id); return id; }, readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { var t = Element._attributeTranslations.read; if (t.values[name]) return t.values[name](element, name); if (t.names[name]) name = t.names[name]; if (name.include(':')) { return (!element.attributes || !element.attributes[name]) ? null : element.attributes[name].value; } } return element.getAttribute(name); }, writeAttribute: function(element, name, value) { element = $(element); var attributes = { }, t = Element._attributeTranslations.write; if (typeof name == 'object') attributes = name; else attributes[name] = Object.isUndefined(value) ? true : value; for (var attr in attributes) { name = t.names[attr] || attr; value = attributes[attr]; if (t.values[attr]) name = t.values[attr](element, value); if (value === false || value === null) element.removeAttribute(name); else if (value === true) element.setAttribute(name, name); else element.setAttribute(name, value); } return element; }, getHeight: function(element) { return $(element).getDimensions().height; }, getWidth: function(element) { return $(element).getDimensions().width; }, classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; var elementClassName = element.className; return (elementClassName.length > 0 && (elementClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); }, addClassName: function(element, className) { if (!(element = $(element))) return; if (!element.hasClassName(className)) element.className += (element.className ? ' ' : '') + className; return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; element.className = element.className.replace( new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); return element; }, toggleClassName: function(element, className) { if (!(element = $(element))) return; return element[element.hasClassName(className) ? 'removeClassName' : 'addClassName'](className); }, // removes whitespace-only text node children cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; while (node) { var nextNode = node.nextSibling; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) element.removeChild(node); node = nextNode; } return element; }, empty: function(element) { return $(element).innerHTML.blank(); }, descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains) return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode) if (element == ancestor) return true; return false; }, scrollTo: function(element) { element = $(element); var pos = element.cumulativeOffset(); window.scrollTo(pos[0], pos[1]); return element; }, getStyle: function(element, style) { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; if (!value || value == 'auto') { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } if (style == 'opacity') return value ? parseFloat(value) : 1.0; return value == 'auto' ? null : value; }, getOpacity: function(element) { return $(element).getStyle('opacity'); }, setStyle: function(element, styles) { element = $(element); var elementStyle = element.style, match; if (Object.isString(styles)) { element.style.cssText += ';' + styles; return styles.include('opacity') ? element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; } for (var property in styles) if (property == 'opacity') element.setOpacity(styles[property]); else elementStyle[(property == 'float' || property == 'cssFloat') ? (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : property] = styles[property]; return element; }, setOpacity: function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }, getDimensions: function(element) { element = $(element); var display = element.getStyle('display'); if (display != 'none' && display != null) // Safari bug return {width: element.offsetWidth, height: element.offsetHeight}; // All *Width and *Height properties give 0 on elements with display none, // so enable the element temporarily var els = element.style; var originalVisibility = els.visibility; var originalPosition = els.position; var originalDisplay = els.display; els.visibility = 'hidden'; els.position = 'absolute'; els.display = 'block'; var originalWidth = element.clientWidth; var originalHeight = element.clientHeight; els.display = originalDisplay; els.position = originalPosition; els.visibility = originalVisibility; return {width: originalWidth, height: originalHeight}; }, makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; // Opera returns the offset relative to the positioning context, when an // element is position relative but top and left have not been defined if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; } } return element; }, undoPositioned: function(element) { element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; } return element; }, makeClipping: function(element) { element = $(element); if (element._overflow) return element; element._overflow = Element.getStyle(element, 'overflow') || 'auto'; if (element._overflow !== 'hidden') element.style.overflow = 'hidden'; return element; }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (element.tagName.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (element.getStyle('position') == 'absolute') return element; // Position.prepare(); // To be done manually by Scripty when it needs it. var offsets = element.positionedOffset(); var top = offsets[1]; var left = offsets[0]; var width = element.clientWidth; var height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; return element; }, relativize: function(element) { element = $(element); if (element.getStyle('position') == 'relative') return element; // Position.prepare(); // To be done manually by Scripty when it needs it. element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; return element; }, cumulativeScrollOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return Element._returnOffset(valueL, valueT); }, getOffsetParent: function(element) { if (element.offsetParent) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }, viewportOffset: function(forElement) { var valueT = 0, valueL = 0; var element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; // Safari fix if (element.offsetParent == document.body && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return Element._returnOffset(valueL, valueT); }, clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || { }); // find page position of source source = $(source); var p = source.viewportOffset(); // find coordinate system to use element = $(element); var delta = [0, 0]; var parent = null; // delta [0,0] will do fine with position: fixed elements, // position:absolute needs offsetParent deltas if (Element.getStyle(element, 'position') == 'absolute') { parent = element.getOffsetParent(); delta = parent.viewportOffset(); } // correct by body offsets (fixes Safari) if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } // set position if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; if (options.setHeight) element.style.height = source.offsetHeight + 'px'; return element; } }; Element.Methods.identify.counter = 1; Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, childElements: Element.Methods.immediateDescendants }); Element._attributeTranslations = { write: { names: { className: 'class', htmlFor: 'for' }, values: { } } }; if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { case 'left': case 'top': case 'right': case 'bottom': if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': // returns '0px' for hidden elements; we want it to return null if (!Element.visible(element)) return null; // returns the border-box dimensions rather than the content-box // dimensions, so we subtract padding and borders from the value var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()]) return dim + 'px'; var properties; if (style === 'height') { properties = ['border-top-width', 'padding-top', 'padding-bottom', 'border-bottom-width']; } else { properties = ['border-left-width', 'padding-left', 'padding-right', 'border-right-width']; } return properties.inject(dim, function(memo, property) { var val = proceed(element, property); return val === null ? memo : memo - parseInt(val, 10); }) + 'px'; default: return proceed(element, style); } } ); Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( function(proceed, element, attribute) { if (attribute === 'title') return element.title; return proceed(element, attribute); } ); } else if (Prototype.Browser.IE) { // IE doesn't report offsets correctly for static elements, so we change them // to "relative" to get the values, then change them back. Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); // IE throws an error if element is not in document try { element.offsetParent } catch(e) { return $(document.body) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); $w('positionedOffset viewportOffset').each(function(method) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); try { element.offsetParent } catch(e) { return Element._returnOffset(0,0) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); // Trigger hasLayout on the offset parent so that IE6 reports // accurate offsetTop and offsetLeft values for position: fixed. var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); }); Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( function(proceed, element) { try { element.offsetParent } catch(e) { return Element._returnOffset(0,0) } return proceed(element); } ); Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity') { if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) if (value[1]) return parseFloat(value[1]) / 100; return 1.0; } if (value == 'auto') { if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) return element['offset' + style.capitalize()] + 'px'; return null; } return value; }; Element.Methods.setOpacity = function(element, value) { function stripAlpha(filter){ return filter.replace(/alpha\([^\)]*\)/gi,''); } element = $(element); var currentStyle = element.currentStyle; if ((currentStyle && !currentStyle.hasLayout) || (!currentStyle && element.style.zoom == 'normal')) element.style.zoom = 1; var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { (filter = stripAlpha(filter)) ? style.filter = filter : style.removeAttribute('filter'); return element; } else if (value < 0.00001) value = 0; style.filter = stripAlpha(filter) + 'alpha(opacity=' + (value * 100) + ')'; return element; }; Element._attributeTranslations = { read: { names: { 'class': 'className', 'for': 'htmlFor' }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute, 2); }, _getAttrNode: function(element, attribute) { var node = element.getAttributeNode(attribute); return node ? node.value : ""; }, _getEv: function(element, attribute) { attribute = element.getAttribute(attribute); return attribute ? attribute.toString().slice(23, -2) : null; }, _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { return element.title; } } } }; Element._attributeTranslations.write = { names: Object.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, Element._attributeTranslations.read.names), values: { checked: function(element, value) { element.checked = !!value; }, style: function(element, value) { element.style.cssText = value ? value : ''; } } }; Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); (function(v) { Object.extend(v, { href: v._getAttr, src: v._getAttr, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, checked: v._flag, readonly: v._flag, multiple: v._flag, onload: v._getEv, onunload: v._getEv, onclick: v._getEv, ondblclick: v._getEv, onmousedown: v._getEv, onmouseup: v._getEv, onmouseover: v._getEv, onmousemove: v._getEv, onmouseout: v._getEv, onfocus: v._getEv, onblur: v._getEv, onkeypress: v._getEv, onkeydown: v._getEv, onkeyup: v._getEv, onsubmit: v._getEv, onreset: v._getEv, onselect: v._getEv, onchange: v._getEv }); })(Element._attributeTranslations.read.values); } else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; } else if (Prototype.Browser.WebKit) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; if (value == 1) if(element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { } return element; }; // Safari returns margins on body which is incorrect if the child is absolutely // positioned. For performance reasons, redefine Element#cumulativeOffset for // KHTML/WebKit only. Element.Methods.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }; } if (Prototype.Browser.IE || Prototype.Browser.Opera) { // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements Element.Methods.update = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); var tagName = element.tagName.toUpperCase(); if (tagName in Element._insertionTranslations.tags) { $A(element.childNodes).each(function(node) { element.removeChild(node) }); Element._getContentFromAnonymousElement(tagName, content.stripScripts()) .each(function(node) { element.appendChild(node) }); } else element.innerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } if ('outerHTML' in document.createElement('div')) { Element.Methods.replace = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { element.parentNode.replaceChild(content, element); return element; } content = Object.toHTML(content); var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName]) { var nextSibling = element.next(); var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling) fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); else fragments.each(function(node) { parent.appendChild(node) }); } else element.outerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } Element._returnOffset = function(l, t) { var result = [l, t]; result.left = l; result.top = t; return result; }; Element._getContentFromAnonymousElement = function(tagName, html) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; t[2].times(function() { div = div.firstChild }); } else div.innerHTML = html; return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['
    Site:<%= @oidreq.trust_root %>
    ', '
    ', 1], TBODY: ['', '
    ', 2], TR: ['', '
    ', 3], TD: ['
    ', '
    ', 4], SELECT: ['', 1] } }; (function() { Object.extend(this.tags, { THEAD: this.tags.TBODY, TFOOT: this.tags.TBODY, TH: this.tags.TD }); }).call(Element._insertionTranslations); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); return !!(node && node.specified); } }; Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); if (!Prototype.BrowserFeatures.ElementExtensions && document.createElement('div')['__proto__']) { window.HTMLElement = { }; window.HTMLElement.prototype = document.createElement('div')['__proto__']; Prototype.BrowserFeatures.ElementExtensions = true; } Element.extend = (function() { if (Prototype.BrowserFeatures.SpecificElementExtensions) return Prototype.K; var Methods = { }, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element) { if (!element || element._extendedByPrototype || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), tagName = element.tagName.toUpperCase(), property, value; // extend methods for specific tags if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); for (property in methods) { value = methods[property]; if (Object.isFunction(value) && !(property in element)) element[property] = value.methodize(); } element._extendedByPrototype = Prototype.emptyFunction; return element; }, { refresh: function() { // extend methods for all tags (Safari doesn't need this) if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); } } }); extend.refresh(); return extend; })(); Element.hasAttribute = function(element, attribute) { if (element.hasAttribute) return element.hasAttribute(attribute); return Element.Methods.Simulated.hasAttribute(element, attribute); }; Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); } if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; } if (!tagName) Object.extend(Element.Methods, methods || { }); else { if (Object.isArray(tagName)) tagName.each(extend); else extend(tagName); } function extend(tagName) { tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName]) Element.Methods.ByTag[tagName] = { }; Object.extend(Element.Methods.ByTag[tagName], methods); } function copy(methods, destination, onlyIfAbsent) { onlyIfAbsent = onlyIfAbsent || false; for (var property in methods) { var value = methods[property]; if (!Object.isFunction(value)) continue; if (!onlyIfAbsent || !(property in destination)) destination[property] = value.methodize(); } } function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; window[klass] = { }; window[klass].prototype = document.createElement(tagName)['__proto__']; return window[klass]; } if (F.ElementExtensions) { copy(Element.Methods, HTMLElement.prototype); copy(Element.Methods.Simulated, HTMLElement.prototype, true); } if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (Object.isUndefined(klass)) continue; copy(T[tag], klass.prototype); } } Object.extend(Element, Element.Methods); delete Element.ByTag; if (Element.extend.refresh) Element.extend.refresh(); Element.cache = { }; }; document.viewport = { getDimensions: function() { var dimensions = { }, B = Prototype.Browser; $w('width height').each(function(d) { var D = d.capitalize(); if (B.WebKit && !document.evaluate) { // Safari <3.0 needs self.innerWidth/Height dimensions[d] = self['inner' + D]; } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { // Opera <9.5 needs document.body.clientWidth/Height dimensions[d] = document.body['client' + D] } else { dimensions[d] = document.documentElement['client' + D]; } }); return dimensions; }, getWidth: function() { return this.getDimensions().width; }, getHeight: function() { return this.getDimensions().height; }, getScrollOffsets: function() { return Element._returnOffset( window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; /* Portions of the Selector class are derived from Jack Slocum's DomQuery, * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style * license. Please see http://www.yui-ext.com/ for more information. */ var Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); if (this.shouldUseSelectorsAPI()) { this.mode = 'selectorsAPI'; } else if (this.shouldUseXPath()) { this.mode = 'xpath'; this.compileXPathMatcher(); } else { this.mode = "normal"; this.compileMatcher(); } }, shouldUseXPath: function() { if (!Prototype.BrowserFeatures.XPath) return false; var e = this.expression; // Safari 3 chokes on :*-of-type and :empty if (Prototype.Browser.WebKit && (e.include("-of-type") || e.include(":empty"))) return false; // XPath can't do namespaced attributes, nor can it read // the "checked" property from DOM nodes if ((/(\[[\w-]*?:|:checked)/).test(e)) return false; return true; }, shouldUseSelectorsAPI: function() { if (!Prototype.BrowserFeatures.SelectorsAPI) return false; if (!Selector._div) Selector._div = new Element('div'); // Make sure the browser treats the selector as valid. Test on an // isolated element to minimize cost of this check. try { Selector._div.querySelector(this.expression); } catch(e) { return false; } return true; }, compileMatcher: function() { var e = this.expression, ps = Selector.patterns, h = Selector.handlers, c = Selector.criteria, le, p, m; if (Selector._cache[e]) { this.matcher = Selector._cache[e]; return; } this.matcher = ["this.matcher = function(root) {", "var r = root, h = Selector.handlers, c = false, n;"]; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : new Template(c[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } } this.matcher.push("return h.unique(n);\n}"); eval(this.matcher.join('\n')); Selector._cache[this.expression] = this.matcher; }, compileXPathMatcher: function() { var e = this.expression, ps = Selector.patterns, x = Selector.xpath, le, m; if (Selector._cache[e]) { this.xpath = Selector._cache[e]; return; } this.matcher = ['.//*']; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { if (m = e.match(ps[i])) { this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } } this.xpath = this.matcher.join(''); Selector._cache[this.expression] = this.xpath; }, findElements: function(root) { root = root || document; var e = this.expression, results; switch (this.mode) { case 'selectorsAPI': // querySelectorAll queries document-wide, then filters to descendants // of the context element. That's not what we want. // Add an explicit context to the selector if necessary. if (root !== document) { var oldId = root.id, id = $(root).identify(); e = "#" + id + " " + e; } results = $A(root.querySelectorAll(e)).map(Element.extend); root.id = oldId; return results; case 'xpath': return document._getElementsByXPath(this.xpath, root); default: return this.matcher(root); } }, match: function(element) { this.tokens = []; var e = this.expression, ps = Selector.patterns, as = Selector.assertions; var le, p, m; while (e && le !== e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { // use the Selector.assertions methods unless the selector // is too complex. if (as[i]) { this.tokens.push([i, Object.clone(m)]); e = e.replace(m[0], ''); } else { // reluctantly do a document-wide search // and look for a match in the array return this.findElements(document).include(element); } } } } var match = true, name, matches; for (var i = 0, token; token = this.tokens[i]; i++) { name = token[0], matches = token[1]; if (!Selector.assertions[name](element, matches)) { match = false; break; } } return match; }, toString: function() { return this.expression; }, inspect: function() { return "#"; } }); Object.extend(Selector, { _cache: { }, xpath: { descendant: "//*", child: "/*", adjacent: "/following-sibling::*[1]", laterSibling: '/following-sibling::*', tagName: function(m) { if (m[1] == '*') return ''; return "[local-name()='" + m[1].toLowerCase() + "' or local-name()='" + m[1].toUpperCase() + "']"; }, className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", id: "[@id='#{1}']", attrPresence: function(m) { m[1] = m[1].toLowerCase(); return new Template("[@#{1}]").evaluate(m); }, attr: function(m) { m[1] = m[1].toLowerCase(); m[3] = m[5] || m[6]; return new Template(Selector.xpath.operators[m[2]]).evaluate(m); }, pseudo: function(m) { var h = Selector.xpath.pseudos[m[1]]; if (!h) return ''; if (Object.isFunction(h)) return h(m); return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); }, operators: { '=': "[@#{1}='#{3}']", '!=': "[@#{1}!='#{3}']", '^=': "[starts-with(@#{1}, '#{3}')]", '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", '*=': "[contains(@#{1}, '#{3}')]", '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" }, pseudos: { 'first-child': '[not(preceding-sibling::*)]', 'last-child': '[not(following-sibling::*)]', 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 'empty': "[count(*) = 0 and (count(text()) = 0)]", 'checked': "[@checked]", 'disabled': "[(@disabled) and (@type!='hidden')]", 'enabled': "[not(@disabled) and (@type!='hidden')]", 'not': function(m) { var e = m[6], p = Selector.patterns, x = Selector.xpath, le, v; var exclusion = []; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in p) { if (m = e.match(p[i])) { v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); exclusion.push("(" + v.substring(1, v.length - 1) + ")"); e = e.replace(m[0], ''); break; } } } return "[not(" + exclusion.join(" and ") + ")]"; }, 'nth-child': function(m) { return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); }, 'nth-last-child': function(m) { return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); }, 'nth-of-type': function(m) { return Selector.xpath.pseudos.nth("position() ", m); }, 'nth-last-of-type': function(m) { return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); }, 'first-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); }, 'last-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); }, 'only-of-type': function(m) { var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); }, nth: function(fragment, m) { var mm, formula = m[6], predicate; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; if (mm = formula.match(/^(\d+)$/)) // digit only return '[' + fragment + "= " + mm[1] + ']'; if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (mm[1] == "-") mm[1] = -1; var a = mm[1] ? Number(mm[1]) : 1; var b = mm[2] ? Number(mm[2]) : 0; predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + "((#{fragment} - #{b}) div #{a} >= 0)]"; return new Template(predicate).evaluate({ fragment: fragment, a: a, b: b }); } } } }, criteria: { tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', className: 'n = h.className(n, r, "#{1}", c); c = false;', id: 'n = h.id(n, r, "#{1}", c); c = false;', attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', attr: function(m) { m[3] = (m[5] || m[6]); return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); }, pseudo: function(m) { if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); }, descendant: 'c = "descendant";', child: 'c = "child";', adjacent: 'c = "adjacent";', laterSibling: 'c = "laterSibling";' }, patterns: { // combinators must be listed first // (and descendant needs to be last combinator) laterSibling: /^\s*~\s*/, child: /^\s*>\s*/, adjacent: /^\s*\+\s*/, descendant: /^\s/, // selectors follow tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, id: /^#([\w\-\*]+)(\b|$)/, className: /^\.([\w\-\*]+)(\b|$)/, pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }, // for Selector.match and Element#match assertions: { tagName: function(element, matches) { return matches[1].toUpperCase() == element.tagName.toUpperCase(); }, className: function(element, matches) { return Element.hasClassName(element, matches[1]); }, id: function(element, matches) { return element.id === matches[1]; }, attrPresence: function(element, matches) { return Element.hasAttribute(element, matches[1]); }, attr: function(element, matches) { var nodeValue = Element.readAttribute(element, matches[1]); return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); } }, handlers: { // UTILITY FUNCTIONS // joins two collections concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) a.push(node); return a; }, // marks an array of nodes for counting mark: function(nodes) { var _true = Prototype.emptyFunction; for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = _true; return nodes; }, unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = undefined; return nodes; }, // mark each child node with its position (for nth calls) // "ofType" flag indicates whether we're indexing for nth-of-type // rather than nth-child index: function(parentNode, reverse, ofType) { parentNode._countedByPrototype = Prototype.emptyFunction; if (reverse) { for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { var node = nodes[i]; if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } } else { for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } }, // filters out duplicates and extends all nodes unique: function(nodes) { if (nodes.length == 0) return nodes; var results = [], n; for (var i = 0, l = nodes.length; i < l; i++) if (!(n = nodes[i])._countedByPrototype) { n._countedByPrototype = Prototype.emptyFunction; results.push(Element.extend(n)); } return Selector.handlers.unmark(results); }, // COMBINATOR FUNCTIONS descendant: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName('*')); return results; }, child: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) { for (var j = 0, child; child = node.childNodes[j]; j++) if (child.nodeType == 1 && child.tagName != '!') results.push(child); } return results; }, adjacent: function(nodes) { for (var i = 0, results = [], node; node = nodes[i]; i++) { var next = this.nextElementSibling(node); if (next) results.push(next); } return results; }, laterSibling: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, Element.nextSiblings(node)); return results; }, nextElementSibling: function(node) { while (node = node.nextSibling) if (node.nodeType == 1) return node; return null; }, previousElementSibling: function(node) { while (node = node.previousSibling) if (node.nodeType == 1) return node; return null; }, // TOKEN FUNCTIONS tagName: function(nodes, root, tagName, combinator) { var uTagName = tagName.toUpperCase(); var results = [], h = Selector.handlers; if (nodes) { if (combinator) { // fastlane for ordinary descendant combinators if (combinator == "descendant") { for (var i = 0, node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName(tagName)); return results; } else nodes = this[combinator](nodes); if (tagName == "*") return nodes; } for (var i = 0, node; node = nodes[i]; i++) if (node.tagName.toUpperCase() === uTagName) results.push(node); return results; } else return root.getElementsByTagName(tagName); }, id: function(nodes, root, id, combinator) { var targetNode = $(id), h = Selector.handlers; if (!targetNode) return []; if (!nodes && root == document) return [targetNode]; if (nodes) { if (combinator) { if (combinator == 'child') { for (var i = 0, node; node = nodes[i]; i++) if (targetNode.parentNode == node) return [targetNode]; } else if (combinator == 'descendant') { for (var i = 0, node; node = nodes[i]; i++) if (Element.descendantOf(targetNode, node)) return [targetNode]; } else if (combinator == 'adjacent') { for (var i = 0, node; node = nodes[i]; i++) if (Selector.handlers.previousElementSibling(targetNode) == node) return [targetNode]; } else nodes = h[combinator](nodes); } for (var i = 0, node; node = nodes[i]; i++) if (node == targetNode) return [targetNode]; return []; } return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; }, className: function(nodes, root, className, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); return Selector.handlers.byClassName(nodes, root, className); }, byClassName: function(nodes, root, className) { if (!nodes) nodes = Selector.handlers.descendant([root]); var needle = ' ' + className + ' '; for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { nodeClassName = node.className; if (nodeClassName.length == 0) continue; if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) results.push(node); } return results; }, attrPresence: function(nodes, root, attr, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var results = []; for (var i = 0, node; node = nodes[i]; i++) if (Element.hasAttribute(node, attr)) results.push(node); return results; }, attr: function(nodes, root, attr, value, operator, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var handler = Selector.operators[operator], results = []; for (var i = 0, node; node = nodes[i]; i++) { var nodeValue = Element.readAttribute(node, attr); if (nodeValue === null) continue; if (handler(nodeValue, value)) results.push(node); } return results; }, pseudo: function(nodes, name, value, root, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); if (!nodes) nodes = root.getElementsByTagName("*"); return Selector.pseudos[name](nodes, value, root); } }, pseudos: { 'first-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.previousElementSibling(node)) continue; results.push(node); } return results; }, 'last-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.nextElementSibling(node)) continue; results.push(node); } return results; }, 'only-child': function(nodes, value, root) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) results.push(node); return results; }, 'nth-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root); }, 'nth-last-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true); }, 'nth-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, false, true); }, 'nth-last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true, true); }, 'first-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, false, true); }, 'last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, true, true); }, 'only-of-type': function(nodes, formula, root) { var p = Selector.pseudos; return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); }, // handles the an+b logic getIndices: function(a, b, total) { if (a == 0) return b > 0 ? [b] : []; return $R(1, total).inject([], function(memo, i) { if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); return memo; }); }, // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type nth: function(nodes, formula, root, reverse, ofType) { if (nodes.length == 0) return []; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; var h = Selector.handlers, results = [], indexed = [], m; h.mark(nodes); for (var i = 0, node; node = nodes[i]; i++) { if (!node.parentNode._countedByPrototype) { h.index(node.parentNode, reverse, ofType); indexed.push(node.parentNode); } } if (formula.match(/^\d+$/)) { // just a number formula = Number(formula); for (var i = 0, node; node = nodes[i]; i++) if (node.nodeIndex == formula) results.push(node); } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (m[1] == "-") m[1] = -1; var a = m[1] ? Number(m[1]) : 1; var b = m[2] ? Number(m[2]) : 0; var indices = Selector.pseudos.getIndices(a, b, nodes.length); for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { for (var j = 0; j < l; j++) if (node.nodeIndex == indices[j]) results.push(node); } } h.unmark(nodes); h.unmark(indexed); return results; }, 'empty': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { // IE treats comments as element nodes if (node.tagName == '!' || node.firstChild) continue; results.push(node); } return results; }, 'not': function(nodes, selector, root) { var h = Selector.handlers, selectorType, m; var exclusions = new Selector(selector).findElements(root); h.mark(exclusions); for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node._countedByPrototype) results.push(node); h.unmark(exclusions); return results; }, 'enabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node.disabled && (!node.type || node.type !== 'hidden')) results.push(node); return results; }, 'disabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.disabled) results.push(node); return results; }, 'checked': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.checked) results.push(node); return results; } }, operators: { '=': function(nv, v) { return nv == v; }, '!=': function(nv, v) { return nv != v; }, '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, '$=': function(nv, v) { return nv.endsWith(v); }, '*=': function(nv, v) { return nv.include(v); }, '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + '-').include('-' + (v || "").toUpperCase() + '-'); } }, split: function(expression) { var expressions = []; expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { expressions.push(m[1].strip()); }); return expressions; }, matchElements: function(elements, expression) { var matches = $$(expression), h = Selector.handlers; h.mark(matches); for (var i = 0, results = [], element; element = elements[i]; i++) if (element._countedByPrototype) results.push(element); h.unmark(matches); return results; }, findElement: function(elements, expression, index) { if (Object.isNumber(expression)) { index = expression; expression = false; } return Selector.matchElements(elements, expression || '*')[index || 0]; }, findChildElements: function(element, expressions) { expressions = Selector.split(expressions.join(',')); var results = [], h = Selector.handlers; for (var i = 0, l = expressions.length, selector; i < l; i++) { selector = new Selector(expressions[i].strip()); h.concat(results, selector.findElements(element)); } return (l > 1) ? h.unique(results) : results; } }); if (Prototype.Browser.IE) { Object.extend(Selector.handlers, { // IE returns comment nodes on getElementsByTagName("*"). // Filter them out. concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) if (node.tagName !== "!") a.push(node); return a; }, // IE improperly serializes _countedByPrototype in (inner|outer)HTML. unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node.removeAttribute('_countedByPrototype'); return nodes; } }); } function $$() { return Selector.findChildElements(document, $A(arguments)); } var Form = { reset: function(form) { $(form).reset(); return form; }, serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; var key, value, submitted = false, submit = options.submit; var data = elements.inject({ }, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { if (key in result) { // a key is already present; construct an array of values if (!Object.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); } else result[key] = value; } } return result; }); return options.hash ? data : Object.toQueryString(data); } }; Form.Methods = { serialize: function(form, options) { return Form.serializeElements(Form.getElements(form), options); }, getElements: function(form) { return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) { if (Form.Element.Serializers[child.tagName.toLowerCase()]) elements.push(Element.extend(child)); return elements; } ); }, getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { var elements = $(form).getElements().findAll(function(element) { return 'hidden' != element.type && !element.disabled; }); var firstByIndex = elements.findAll(function(element) { return element.hasAttribute('tabIndex') && element.tabIndex >= 0; }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options) { form = $(form), options = Object.clone(options || { }); var params = options.parameters, action = form.readAttribute('action') || ''; if (action.blank()) action = window.location.href; options.parameters = form.serialize(true); if (params) { if (Object.isString(params)) params = params.toQueryParams(); Object.extend(options.parameters, params); } if (form.hasAttribute('method') && !options.method) options.method = form.method; return new Ajax.Request(action, options); } }; /*--------------------------------------------------------------------------*/ Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } }; Form.Element.Methods = { serialize: function(element) { element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = { }; pair[element.name] = value; return Object.toQueryString(pair); } } return ''; }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, setValue: function(element, value) { element = $(element); var method = element.tagName.toLowerCase(); Form.Element.Serializers[method](element, value); return element; }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element) { element = $(element); try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !['button', 'reset', 'submit'].include(element.type))) element.select(); } catch (e) { } return element; }, disable: function(element) { element = $(element); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } }; /*--------------------------------------------------------------------------*/ var Field = Form.Element; var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ Form.Element.Serializers = { input: function(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element, value); default: return Form.Element.Serializers.textarea(element, value); } }, inputSelector: function(element, value) { if (Object.isUndefined(value)) return element.checked ? element.value : null; else element.checked = !!value; }, textarea: function(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; }, select: function(element, value) { if (Object.isUndefined(value)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; currentValue = this.optionValue(opt); if (single) { if (currentValue == value) { opt.selected = true; return; } } else opt.selected = value.include(currentValue); } } }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); } return values; }, optionValue: function(opt) { // extend element because hasAttribute may not be native return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } }; /*--------------------------------------------------------------------------*/ Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); this.element = $(element); this.lastValue = this.getValue(); }, execute: function() { var value = this.getValue(); if (Object.isString(this.lastValue) && Object.isString(value) ? this.lastValue != value : String(this.lastValue) != String(value)) { this.callback(this.element, value); this.lastValue = value; } } }); Form.Element.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.serialize(this.element); } }); /*--------------------------------------------------------------------------*/ Abstract.EventObserver = Class.create({ initialize: function(element, callback) { this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback, this); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } }); Form.Element.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.serialize(this.element); } }); if (!window.Event) var Event = { }; Object.extend(Event, { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_INSERT: 45, cache: { }, relatedTarget: function(event) { var element; switch(event.type) { case 'mouseover': element = event.fromElement; break; case 'mouseout': element = event.toElement; break; default: return null; } return Element.extend(element); } }); Event.Methods = (function() { var isButton; if (Prototype.Browser.IE) { var buttonMap = { 0: 1, 1: 4, 2: 2 }; isButton = function(event, code) { return event.button == buttonMap[code]; }; } else if (Prototype.Browser.WebKit) { isButton = function(event, code) { switch (code) { case 0: return event.which == 1 && !event.metaKey; case 1: return event.which == 1 && event.metaKey; default: return false; } }; } else { isButton = function(event, code) { return event.which ? (event.which === code + 1) : (event.button === code); }; } return { isLeftClick: function(event) { return isButton(event, 0) }, isMiddleClick: function(event) { return isButton(event, 1) }, isRightClick: function(event) { return isButton(event, 2) }, element: function(event) { event = Event.extend(event); var node = event.target, type = event.type, currentTarget = event.currentTarget; if (currentTarget && currentTarget.tagName) { // Firefox screws up the "click" event when moving between radio buttons // via arrow keys. It also screws up the "load" and "error" events on images, // reporting the document as the target instead of the original image. if (type === 'load' || type === 'error' || (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' && currentTarget.type === 'radio')) node = currentTarget; } if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; return Element.extend(node); }, findElement: function(event, expression) { var element = Event.element(event); if (!expression) return element; var elements = [element].concat(element.ancestors()); return Selector.findElement(elements, expression, 0); }, pointer: function(event) { var docElement = document.documentElement, body = document.body || { scrollLeft: 0, scrollTop: 0 }; return { x: event.pageX || (event.clientX + (docElement.scrollLeft || body.scrollLeft) - (docElement.clientLeft || 0)), y: event.pageY || (event.clientY + (docElement.scrollTop || body.scrollTop) - (docElement.clientTop || 0)) }; }, pointerX: function(event) { return Event.pointer(event).x }, pointerY: function(event) { return Event.pointer(event).y }, stop: function(event) { Event.extend(event); event.preventDefault(); event.stopPropagation(); event.stopped = true; } }; })(); Event.extend = (function() { var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); if (Prototype.Browser.IE) { Object.extend(methods, { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return "[object Event]" } }); return function(event) { if (!event) return false; if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; var pointer = Event.pointer(event); Object.extend(event, { target: event.srcElement, relatedTarget: Event.relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); return Object.extend(event, methods); }; } else { Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; Object.extend(Event.prototype, methods); return Prototype.K; } })(); Object.extend(Event, (function() { var cache = Event.cache; function getEventID(element) { if (element._prototypeEventID) return element._prototypeEventID[0]; arguments.callee.id = arguments.callee.id || 1; return element._prototypeEventID = [++arguments.callee.id]; } function getDOMEventName(eventName) { if (eventName && eventName.include(':')) return "dataavailable"; return eventName; } function getCacheForID(id) { return cache[id] = cache[id] || { }; } function getWrappersForEventName(id, eventName) { var c = getCacheForID(id); return c[eventName] = c[eventName] || []; } function createWrapper(element, eventName, handler) { var id = getEventID(element); var c = getWrappersForEventName(id, eventName); if (c.pluck("handler").include(handler)) return false; var wrapper = function(event) { if (!Event || !Event.extend || (event.eventName && event.eventName != eventName)) return false; Event.extend(event); handler.call(element, event); }; wrapper.handler = handler; c.push(wrapper); return wrapper; } function findWrapper(id, eventName, handler) { var c = getWrappersForEventName(id, eventName); return c.find(function(wrapper) { return wrapper.handler == handler }); } function destroyWrapper(id, eventName, handler) { var c = getCacheForID(id); if (!c[eventName]) return false; c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); } function destroyCache() { for (var id in cache) for (var eventName in cache[id]) cache[id][eventName] = null; } // Internet Explorer needs to remove event handlers on page unload // in order to avoid memory leaks. if (window.attachEvent) { window.attachEvent("onunload", destroyCache); } // Safari has a dummy event handler on page unload so that it won't // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" // object when page is returned to via the back button using its bfcache. if (Prototype.Browser.WebKit) { window.addEventListener('unload', Prototype.emptyFunction, false); } return { observe: function(element, eventName, handler) { element = $(element); var name = getDOMEventName(eventName); var wrapper = createWrapper(element, eventName, handler); if (!wrapper) return element; if (element.addEventListener) { element.addEventListener(name, wrapper, false); } else { element.attachEvent("on" + name, wrapper); } return element; }, stopObserving: function(element, eventName, handler) { element = $(element); var id = getEventID(element), name = getDOMEventName(eventName); if (!handler && eventName) { getWrappersForEventName(id, eventName).each(function(wrapper) { element.stopObserving(eventName, wrapper.handler); }); return element; } else if (!eventName) { Object.keys(getCacheForID(id)).each(function(eventName) { element.stopObserving(eventName); }); return element; } var wrapper = findWrapper(id, eventName, handler); if (!wrapper) return element; if (element.removeEventListener) { element.removeEventListener(name, wrapper, false); } else { element.detachEvent("on" + name, wrapper); } destroyWrapper(id, eventName, handler); return element; }, fire: function(element, eventName, memo) { element = $(element); if (element == document && document.createEvent && !element.dispatchEvent) element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent("HTMLEvents"); event.initEvent("dataavailable", true, true); } else { event = document.createEventObject(); event.eventType = "ondataavailable"; } event.eventName = eventName; event.memo = memo || { }; if (document.createEvent) { element.dispatchEvent(event); } else { element.fireEvent(event.eventType, event); } return Event.extend(event); } }; })()); Object.extend(Event, Event.Methods); Element.addMethods({ fire: Event.fire, observe: Event.observe, stopObserving: Event.stopObserving }); Object.extend(document, { fire: Element.Methods.fire.methodize(), observe: Element.Methods.observe.methodize(), stopObserving: Element.Methods.stopObserving.methodize(), loaded: false }); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, Matthias Miller, Dean Edwards and John Resig. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearInterval(timer); document.fire("dom:loaded"); document.loaded = true; } if (document.addEventListener) { if (Prototype.Browser.WebKit) { timer = window.setInterval(function() { if (/loaded|complete/.test(document.readyState)) fireContentLoadedEvent(); }, 0); Event.observe(window, "load", fireContentLoadedEvent); } else { document.addEventListener("DOMContentLoaded", fireContentLoadedEvent, false); } } else { document.write("