├── admin
├── library-name
├── fixperms
├── build-docs
├── runtests
├── prepare-release
├── mkassoc
├── graph-require.sh
└── gettlds.py
├── examples
├── rails_openid
│ ├── log
│ │ └── .gitkeep
│ ├── app
│ │ ├── mailers
│ │ │ └── .gitkeep
│ │ ├── models
│ │ │ └── .gitkeep
│ │ ├── helpers
│ │ │ ├── login_helper.rb
│ │ │ ├── application_helper.rb
│ │ │ └── server_helper.rb
│ │ ├── assets
│ │ │ ├── images
│ │ │ │ └── rails.png
│ │ │ ├── stylesheets
│ │ │ │ └── application.css
│ │ │ └── javascripts
│ │ │ │ └── application.js
│ │ ├── controllers
│ │ │ ├── application_controller.rb
│ │ │ └── login_controller.rb
│ │ └── views
│ │ │ ├── server
│ │ │ └── decide.html.erb
│ │ │ ├── layouts
│ │ │ └── server.html.erb
│ │ │ ├── login
│ │ │ └── index.html.erb
│ │ │ └── consumer
│ │ │ └── index.html.erb
│ ├── lib
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ └── tasks
│ │ │ └── .gitkeep
│ ├── public
│ │ ├── favicon.ico
│ │ ├── images
│ │ │ └── openid_login_bg.gif
│ │ ├── javascripts
│ │ │ └── application.js
│ │ ├── robots.txt
│ │ ├── dispatch.cgi
│ │ ├── dispatch.rb
│ │ ├── 500.html
│ │ ├── 422.html
│ │ ├── 404.html
│ │ └── dispatch.fcgi
│ ├── test
│ │ ├── unit
│ │ │ └── .gitkeep
│ │ ├── fixtures
│ │ │ └── .gitkeep
│ │ ├── functional
│ │ │ ├── .gitkeep
│ │ │ ├── login_controller_test.rb
│ │ │ └── server_controller_test.rb
│ │ ├── integration
│ │ │ └── .gitkeep
│ │ ├── performance
│ │ │ └── browsing_test.rb
│ │ └── test_helper.rb
│ ├── db
│ │ ├── development.sqlite3
│ │ └── seeds.rb
│ ├── config
│ │ ├── initializers
│ │ │ ├── rails_root.rb
│ │ │ ├── mime_types.rb
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── session_store.rb
│ │ │ ├── secret_token.rb
│ │ │ ├── wrap_parameters.rb
│ │ │ └── inflections.rb
│ │ ├── environment.rb
│ │ ├── boot.rb
│ │ ├── locales
│ │ │ └── en.yml
│ │ ├── database.yml
│ │ ├── environments
│ │ │ ├── development.rb
│ │ │ ├── test.rb
│ │ │ └── production.rb
│ │ ├── routes.rb
│ │ └── application.rb
│ ├── config.ru
│ ├── doc
│ │ └── README_FOR_APP
│ ├── Rakefile
│ ├── script
│ │ └── rails
│ └── Gemfile
├── active_record_openid_store
│ ├── lib
│ │ ├── nonce.rb
│ │ ├── open_id_setting.rb
│ │ ├── association.rb
│ │ └── openid_ar_store.rb
│ ├── init.rb
│ ├── XXX_upgrade_open_id_store.rb
│ ├── XXX_add_open_id_store_to_db.rb
│ └── README
├── discover
└── README.md
├── lib
├── ruby-openid.rb
├── openid
│ ├── version.rb
│ ├── protocolerror.rb
│ ├── yadis
│ │ ├── constants.rb
│ │ ├── services.rb
│ │ ├── parsehtml.rb
│ │ ├── xri.rb
│ │ ├── xrires.rb
│ │ └── accept.rb
│ ├── consumer
│ │ ├── session.rb
│ │ ├── html_parse.rb
│ │ └── discovery_manager.rb
│ ├── extension.rb
│ ├── extensions
│ │ ├── ui.rb
│ │ └── oauth.rb
│ ├── kvpost.rb
│ ├── urinorm.rb
│ ├── store
│ │ ├── nonce.rb
│ │ ├── memory.rb
│ │ ├── interface.rb
│ │ └── memcache.rb
│ ├── dh.rb
│ ├── util.rb
│ ├── cryptutil.rb
│ └── kvform.rb
├── hmac
│ ├── sha1.rb
│ ├── sha2.rb
│ └── hmac.rb
└── openid.rb
├── test
├── data
│ ├── test_xrds
│ │ ├── not-xrds.xml
│ │ ├── no-xrd.xml
│ │ ├── status222.xrds
│ │ ├── README
│ │ ├── spoof1.xrds
│ │ ├── spoof2.xrds
│ │ ├── =j3h.2007.11.14.xrds
│ │ ├── spoof3.xrds
│ │ ├── delegated-20060809.xrds
│ │ ├── valid-populated-xrds.xml
│ │ ├── delegated-20060809-r1.xrds
│ │ ├── delegated-20060809-r2.xrds
│ │ ├── prefixsometimes.xrds
│ │ ├── sometimesprefix.xrds
│ │ └── subsegments.xrds
│ ├── test_discover
│ │ ├── yadis_no_delegate.xml
│ │ ├── openid_no_delegate.html
│ │ ├── openid2_xrds_no_local_id.xml
│ │ ├── yadis_0entries.xml
│ │ ├── openid2_xrds.xml
│ │ ├── yadis_idp.xml
│ │ ├── openid.html
│ │ ├── openid2.html
│ │ ├── openid_utf8.html
│ │ ├── openid_1_and_2.html
│ │ ├── yadis_idp_delegate.xml
│ │ ├── yadis_another_delegate.xml
│ │ ├── openid_and_yadis.html
│ │ ├── malformed_meta_tag.html
│ │ ├── yadis_2_bad_local_id.xml
│ │ ├── openid_1_and_2_xrds.xml
│ │ ├── openid_1_and_2_xrds_bad_delegate.xml
│ │ ├── yadis_2entries_idp.xml
│ │ └── yadis_2entries_delegate.xml
│ ├── example-xrds.xml
│ ├── urinorm.txt
│ ├── test1-discover.txt
│ ├── accept.txt
│ └── test1-parsehtml.txt
├── test_urinorm.rb
├── util.rb
├── test_extension.rb
├── test_xri.rb
├── test_kvpost.rb
├── test_responses.rb
├── test_parsehtml.rb
├── test_nonce.rb
├── test_dh.rb
├── test_xrires.rb
├── test_ui.rb
├── test_linkparse.rb
├── test_cryptutil.rb
├── testutil.rb
├── test_trustroot.rb
└── test_util.rb
├── NOTICE
├── Gemfile
├── contrib
└── google
│ ├── ruby-openid-apps-discovery-1.0.gem
│ └── ruby-openid-apps-discovery-1.01.gem
├── .gitignore
├── Rakefile
├── .travis.yml
├── ruby-openid.gemspec
├── INSTALL.md
├── CHANGES-2.0.0
├── CHANGES-2.1.0
└── README.md
/admin/library-name:
--------------------------------------------------------------------------------
1 | ruby-openid
--------------------------------------------------------------------------------
/examples/rails_openid/log/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/app/mailers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/app/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/lib/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/lib/tasks/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/test/unit/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/ruby-openid.rb:
--------------------------------------------------------------------------------
1 | require 'openid'
2 |
--------------------------------------------------------------------------------
/examples/rails_openid/db/development.sqlite3:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/test/fixtures/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/test/functional/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/rails_openid/test/integration/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/openid/version.rb:
--------------------------------------------------------------------------------
1 | module OpenID
2 | VERSION = "2.9.2"
3 | end
4 |
--------------------------------------------------------------------------------
/examples/rails_openid/app/helpers/login_helper.rb:
--------------------------------------------------------------------------------
1 | module LoginHelper
2 | end
3 |
--------------------------------------------------------------------------------
/examples/rails_openid/config/initializers/rails_root.rb:
--------------------------------------------------------------------------------
1 | ::RAILS_ROOT = Rails.root
2 |
--------------------------------------------------------------------------------
/test/data/test_xrds/not-xrds.xml:
--------------------------------------------------------------------------------
1 |
2 | foo foo foo こんにちは foo foo Maybe you tried to change something you didn't have access to. You may have mistyped the address or the page may have moved. Welcome to the Ruby OpenID example. This code is a starting point
17 | for developers wishing to implement an OpenID provider or relying
18 | party. We've used the Rails
19 | platform to demonstrate, but the library code is not Rails specific.
23 | The server will automatically create an identity page for
29 | you at <%= @base_url %>user/name Because WEBrick can only handle one thing at a time, you'll need to
32 | run another instance of the example on another port if you want to use
33 | a relying party to use with this example provider: (The RP needs to be able to access the provider, so unless you're
39 | running this example on a public IP, you can't use the live example
40 | at openidenabled.com on
41 | your local provider.)We're sorry, but something went wrong.
23 | The change you wanted was rejected.
23 | The page you were looking for doesn't exist.
23 |
Proceed to step 2 below."
31 | else
32 | flash[:error] = "Sorry, couldn't log you in. Try again."
33 | end
34 |
35 | redirect_to :action => 'index'
36 | end
37 |
38 | def logout
39 | # delete the username from the session hash
40 | session[:username] = nil
41 | session[:approvals] = nil
42 | redirect_to :action => 'index'
43 | end
44 |
45 | end
46 |
--------------------------------------------------------------------------------
/test/util.rb:
--------------------------------------------------------------------------------
1 | # Utilities that are only used in the testing code
2 | require 'stringio'
3 |
4 | module OpenID
5 | module TestUtil
6 | def assert_log_matches(*regexes)
7 | begin
8 | old_logger = Util.logger
9 | log_output = StringIO.new
10 | Util.logger = Logger.new(log_output)
11 | result = yield
12 | ensure
13 | Util.logger = old_logger
14 | end
15 | log_output.rewind
16 | log_lines = log_output.readlines
17 | assert_equal(regexes.length, log_lines.length,
18 | [regexes, log_lines].inspect)
19 | log_lines.zip(regexes) do |line, regex|
20 | assert_match(regex, line)
21 | end
22 | result
23 | end
24 |
25 | def assert_log_line_count(num_lines)
26 | begin
27 | old_logger = Util.logger
28 | log_output = StringIO.new
29 | Util.logger = Logger.new(log_output)
30 | result = yield
31 | ensure
32 | Util.logger = old_logger
33 | end
34 | log_output.rewind
35 | log_lines = log_output.readlines
36 | assert_equal(num_lines, log_lines.length)
37 | result
38 | end
39 |
40 | def silence_logging
41 | begin
42 | old_logger = Util.logger
43 | log_output = StringIO.new
44 | Util.logger = Logger.new(log_output)
45 | result = yield
46 | ensure
47 | Util.logger = old_logger
48 | end
49 | result
50 | end
51 | end
52 | end
53 |
54 |
--------------------------------------------------------------------------------
/lib/openid/yadis/services.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'openid/yadis/filters'
3 | require 'openid/yadis/discovery'
4 | require 'openid/yadis/xrds'
5 |
6 | module OpenID
7 | module Yadis
8 | def Yadis.get_service_endpoints(input_url, flt=nil)
9 | # Perform the Yadis protocol on the input URL and return an
10 | # iterable of resulting endpoint objects.
11 | #
12 | # @param flt: A filter object or something that is convertable
13 | # to a filter object (using mkFilter) that will be used to
14 | # generate endpoint objects. This defaults to generating
15 | # BasicEndpoint objects.
16 | result = Yadis.discover(input_url)
17 | begin
18 | endpoints = Yadis.apply_filter(result.normalized_uri,
19 | result.response_text, flt)
20 | rescue XRDSError => err
21 | raise DiscoveryFailure.new(err.to_s, nil)
22 | end
23 |
24 | return [result.normalized_uri, endpoints]
25 | end
26 |
27 | def Yadis.apply_filter(normalized_uri, xrd_data, flt=nil)
28 | # Generate an iterable of endpoint objects given this input data,
29 | # presumably from the result of performing the Yadis protocol.
30 |
31 | flt = Yadis.make_filter(flt)
32 | et = Yadis.parseXRDS(xrd_data)
33 |
34 | endpoints = []
35 | each_service(et) { |service_element|
36 | endpoints += flt.get_service_endpoints(normalized_uri, service_element)
37 | }
38 |
39 | return endpoints
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/lib/openid/yadis/parsehtml.rb:
--------------------------------------------------------------------------------
1 | require "openid/yadis/htmltokenizer"
2 | require 'cgi'
3 |
4 | module OpenID
5 | module Yadis
6 | def Yadis.html_yadis_location(html)
7 | parser = HTMLTokenizer.new(html)
8 |
9 | # to keep track of whether or not we are in the head element
10 | in_head = false
11 |
12 | begin
13 | while el = parser.getTag('head', '/head', 'meta', 'body', '/body',
14 | 'html', 'script')
15 |
16 | # we are leaving head or have reached body, so we bail
17 | return nil if ['/head', 'body', '/body'].member?(el.tag_name)
18 |
19 | if el.tag_name == 'head'
20 | unless el.to_s[-2] == ?/ # tag ends with a /: a short tag
21 | in_head = true
22 | end
23 | end
24 | next unless in_head
25 |
26 | if el.tag_name == 'script'
27 | unless el.to_s[-2] == ?/ # tag ends with a /: a short tag
28 | parser.getTag('/script')
29 | end
30 | end
31 |
32 | return nil if el.tag_name == 'html'
33 |
34 | if el.tag_name == 'meta' and (equiv = el.attr_hash['http-equiv'])
35 | if ['x-xrds-location','x-yadis-location'].member?(equiv.downcase) &&
36 | el.attr_hash.member?('content')
37 | return CGI::unescapeHTML(el.attr_hash['content'])
38 | end
39 | end
40 | end
41 | rescue HTMLTokenizerError # just stop parsing if there's an error
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/examples/rails_openid/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | RailsOpenid::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Log error messages when you accidentally call methods on nil.
10 | config.whiny_nils = true
11 |
12 | # Show full error reports and disable caching
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger
20 | config.active_support.deprecation = :log
21 |
22 | # Only use best-standards-support built into browsers
23 | config.action_dispatch.best_standards_support = :builtin
24 |
25 | # Raise exception on mass assignment protection for Active Record models
26 | config.active_record.mass_assignment_sanitizer = :strict
27 |
28 | # Log the query plan for queries taking more than this (works
29 | # with SQLite, MySQL, and PostgreSQL)
30 | config.active_record.auto_explain_threshold_in_seconds = 0.5
31 |
32 | # Do not compress assets
33 | config.assets.compress = false
34 |
35 | # Expands the lines which load the assets
36 | config.assets.debug = true
37 | end
38 |
--------------------------------------------------------------------------------
/test/test_extension.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require 'openid/extension'
3 | require 'openid/message'
4 |
5 | module OpenID
6 | class DummyExtension < OpenID::Extension
7 | TEST_URI = 'http://an.extension'
8 | TEST_ALIAS = 'dummy'
9 | def initialize
10 | @ns_uri = TEST_URI
11 | @ns_alias = TEST_ALIAS
12 | end
13 |
14 | def get_extension_args
15 | return {}
16 | end
17 | end
18 |
19 | class ToMessageTest < Minitest::Test
20 | def test_OpenID1
21 | oid1_msg = Message.new(OPENID1_NS)
22 | ext = DummyExtension.new
23 | ext.to_message(oid1_msg)
24 | namespaces = oid1_msg.namespaces
25 | assert(namespaces.implicit?(DummyExtension::TEST_URI))
26 | assert_equal(
27 | DummyExtension::TEST_URI,
28 | namespaces.get_namespace_uri(DummyExtension::TEST_ALIAS))
29 | assert_equal(DummyExtension::TEST_ALIAS,
30 | namespaces.get_alias(DummyExtension::TEST_URI))
31 | end
32 |
33 | def test_OpenID2
34 | oid2_msg = Message.new(OPENID2_NS)
35 | ext = DummyExtension.new
36 | ext.to_message(oid2_msg)
37 | namespaces = oid2_msg.namespaces
38 | assert(!namespaces.implicit?(DummyExtension::TEST_URI))
39 | assert_equal(
40 | DummyExtension::TEST_URI,
41 | namespaces.get_namespace_uri(DummyExtension::TEST_ALIAS))
42 | assert_equal(DummyExtension::TEST_ALIAS,
43 | namespaces.get_alias(DummyExtension::TEST_URI))
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/openid/extensions/ui.rb:
--------------------------------------------------------------------------------
1 | # An implementation of the OpenID User Interface Extension 1.0 - DRAFT 0.5
2 | # see: http://svn.openid.net/repos/specifications/user_interface/1.0/trunk/openid-user-interface-extension-1_0.html
3 |
4 | require 'openid/extension'
5 |
6 | module OpenID
7 |
8 | module UI
9 | NS_URI = "http://specs.openid.net/extensions/ui/1.0"
10 |
11 | class Request < Extension
12 | attr_accessor :lang, :icon, :mode, :ns_alias, :ns_uri
13 | def initialize(mode = nil, icon = nil, lang = nil)
14 | @ns_alias = 'ui'
15 | @ns_uri = NS_URI
16 | @lang = lang
17 | @icon = icon
18 | @mode = mode
19 | end
20 |
21 | def get_extension_args
22 | ns_args = {}
23 | ns_args['lang'] = @lang if @lang
24 | ns_args['icon'] = @icon if @icon
25 | ns_args['mode'] = @mode if @mode
26 | return ns_args
27 | end
28 |
29 | # Instantiate a Request object from the arguments in a
30 | # checkid_* OpenID message
31 | # return nil if the extension was not requested.
32 | def self.from_openid_request(oid_req)
33 | ui_req = new
34 | args = oid_req.message.get_args(NS_URI)
35 | if args == {}
36 | return nil
37 | end
38 | ui_req.parse_extension_args(args)
39 | return ui_req
40 | end
41 |
42 | # Set UI extension parameters
43 | def parse_extension_args(args)
44 | @lang = args["lang"]
45 | @icon = args["icon"]
46 | @mode = args["mode"]
47 | end
48 |
49 | end
50 |
51 | end
52 |
53 | end
54 |
--------------------------------------------------------------------------------
/CHANGES-2.0.0:
--------------------------------------------------------------------------------
1 |
2 | * API Changes
3 | * PAPE (Provider Authentication Policy Extension) module
4 | * Updated extension for specification draft 2
5 | * PAPE::Request::from_success_response returns nil if PAPE
6 | response arguments were not signed
7 | * Added functions to generate request/response HTML forms with
8 | auto-submission javascript
9 | * Consumer (relying party) API:
10 | Auth_OpenID_AuthRequest::htmlMarkup
11 | * Server API: Auth_OpenID_OpenIDResponse::toHTML
12 | * Removed Rails login generator
13 | * SReg::Response::from_success_response returns nil when no signed
14 | arguments were found
15 |
16 | * New Features
17 | * Fetchers now only read/request first megabyte of response
18 |
19 | * Bug fixes
20 | * NOT NULL constraints to tables created by ActiveRecordStore
21 | * check_authentication requests: copy entire response, not just
22 | signed fields. Fixes missing namespace in check_authentication
23 | requests
24 | * OpenID 1 association requests no longer explicitly set
25 | no-encryption session type
26 | * Improved HTML parsing
27 | * AssociationRequest::answer: include session_type in
28 | no-encryption assoc responses
29 | * normalize return_to URL before performing return_to verification
30 | * OpenID::Consumer::IdResHandler.verify_discovery_results_openid1:
31 | fall back to OpenID 1.0 type if 1.1 endpoint cannot be found
32 | * StandardFetcher now includes a timeout setting
33 | * Handle blank content types in
34 | OpenID::Yadis::DiscoveryResult.where_is_yadis?
35 | * Properly convert timestamps to ints before storing in DB, and vise
36 | versa
37 |
--------------------------------------------------------------------------------
/CHANGES-2.1.0:
--------------------------------------------------------------------------------
1 |
2 | * API Changes
3 | * PAPE (Provider Authentication Policy Extension) module
4 | * Updated extension for specification draft 2
5 | * PAPE::Request::from_success_response returns nil if PAPE
6 | response arguments were not signed
7 | * Added functions to generate request/response HTML forms with
8 | auto-submission javascript
9 | * Consumer (relying party) API:
10 | Auth_OpenID_AuthRequest::htmlMarkup
11 | * Server API: Auth_OpenID_OpenIDResponse::toHTML
12 | * Removed Rails login generator
13 | * SReg::Response::from_success_response returns nil when no signed
14 | arguments were found
15 |
16 | * New Features
17 | * Fetchers now only read/request first megabyte of response
18 |
19 | * Bug fixes
20 | * NOT NULL constraints to tables created by ActiveRecordStore
21 | * check_authentication requests: copy entire response, not just
22 | signed fields. Fixes missing namespace in check_authentication
23 | requests
24 | * OpenID 1 association requests no longer explicitly set
25 | no-encryption session type
26 | * Improved HTML parsing
27 | * AssociationRequest::answer: include session_type in
28 | no-encryption assoc responses
29 | * normalize return_to URL before performing return_to verification
30 | * OpenID::Consumer::IdResHandler.verify_discovery_results_openid1:
31 | fall back to OpenID 1.0 type if 1.1 endpoint cannot be found
32 | * StandardFetcher now includes a timeout setting
33 | * Handle blank content types in
34 | OpenID::Yadis::DiscoveryResult.where_is_yadis?
35 | * Properly convert timestamps to ints before storing in DB, and vise
36 | versa
37 |
--------------------------------------------------------------------------------
/examples/rails_openid/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | RailsOpenid::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Configure static asset server for tests with Cache-Control for performance
11 | config.serve_static_assets = true
12 | config.static_cache_control = "public, max-age=3600"
13 |
14 | # Log error messages when you accidentally call methods on nil
15 | config.whiny_nils = true
16 |
17 | # Show full error reports and disable caching
18 | config.consider_all_requests_local = true
19 | config.action_controller.perform_caching = false
20 |
21 | # Raise exceptions instead of rendering exception templates
22 | config.action_dispatch.show_exceptions = false
23 |
24 | # Disable request forgery protection in test environment
25 | config.action_controller.allow_forgery_protection = false
26 |
27 | # Tell Action Mailer not to deliver emails to the real world.
28 | # The :test delivery method accumulates sent emails in the
29 | # ActionMailer::Base.deliveries array.
30 | config.action_mailer.delivery_method = :test
31 |
32 | # Raise exception on mass assignment protection for Active Record models
33 | config.active_record.mass_assignment_sanitizer = :strict
34 |
35 | # Print deprecation notices to the stderr
36 | config.active_support.deprecation = :stderr
37 | end
38 |
--------------------------------------------------------------------------------
/test/test_xri.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require 'openid/yadis/xri'
3 |
4 | module OpenID
5 |
6 | module Yadis
7 |
8 | class XriDiscoveryTestCase < Minitest::Test
9 |
10 | def test_isXRI?
11 | assert_equal(:xri, XRI.identifier_scheme('=john.smith'))
12 | assert_equal(:xri, XRI.identifier_scheme('@smiths/john'))
13 | assert_equal(:xri, XRI.identifier_scheme('xri://=john'))
14 | assert_equal(:xri, XRI.identifier_scheme('@ootao*test1'))
15 | assert_equal(:uri, XRI.identifier_scheme('smoker.myopenid.com'))
16 | assert_equal(:uri, XRI.identifier_scheme('http://smoker.myopenid.com'))
17 | assert_equal(:uri, XRI.identifier_scheme('https://smoker.myopenid.com'))
18 | end
19 | end
20 |
21 | class XriEscapingTestCase < Minitest::Test
22 | def test_escaping_percents
23 | assert_equal('@example/abc%252Fd/ef',
24 | XRI.escape_for_iri('@example/abc%2Fd/ef'))
25 | end
26 |
27 | def test_escaping_xref
28 | # no escapes
29 | assert_equal('@example/foo/(@bar)',
30 | XRI.escape_for_iri('@example/foo/(@bar)'))
31 | # escape slashes
32 | assert_equal('@example/foo/(@bar%2Fbaz)',
33 | XRI.escape_for_iri('@example/foo/(@bar/baz)'))
34 | # escape query ? and fragment #
35 | assert_equal('@example/foo/(@baz%3Fp=q%23r)?i=j#k',
36 | XRI.escape_for_iri('@example/foo/(@baz?p=q#r)?i=j#k'))
37 | end
38 | end
39 |
40 | class XriTransformationTestCase < Minitest::Test
41 | def test_to_iri_normal
42 | assert_equal('xri://@example', XRI.to_iri_normal('@example'))
43 | end
44 | # iri_to_url:
45 | # various ucschar to hex
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/examples/rails_openid/app/views/layouts/server.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
52 | <%= @base_url %>user/<%= session[:username] %>
53 | Ruby OpenID Server Example
57 |
58 |
59 |
60 | <% if flash[:notice] or flash[:error] %>
61 | To use the example provider
22 |
24 |
25 |
48 |
49 |
35 |
37 |
38 | script/server --port=3001
36 |
Visit /consumer 54 | and enter your OpenID.
55 | 56 | 57 | -------------------------------------------------------------------------------- /lib/openid/urinorm.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | 3 | module OpenID 4 | 5 | module URINorm 6 | public 7 | def URINorm.urinorm(uri) 8 | uri = URI.parse(uri) 9 | 10 | raise URI::InvalidURIError.new('no scheme') unless uri.scheme 11 | uri.scheme = uri.scheme.downcase 12 | unless ['http','https'].member?(uri.scheme) 13 | raise URI::InvalidURIError.new('Not an HTTP or HTTPS URI') 14 | end 15 | 16 | raise URI::InvalidURIError.new('no host') unless uri.host 17 | uri.host = uri.host.downcase 18 | 19 | uri.path = remove_dot_segments(uri.path) 20 | uri.path = '/' if uri.path.length == 0 21 | 22 | uri = uri.normalize.to_s 23 | uri = uri.gsub(PERCENT_ESCAPE_RE) { 24 | sub = $&[1..2].to_i(16).chr 25 | reserved(sub) ? $&.upcase : sub 26 | } 27 | 28 | return uri 29 | end 30 | 31 | private 32 | RESERVED_RE = /[A-Za-z0-9._~-]/ 33 | PERCENT_ESCAPE_RE = /%[0-9a-zA-Z]{2}/ 34 | 35 | def URINorm.reserved(chr) 36 | not RESERVED_RE =~ chr 37 | end 38 | 39 | def URINorm.remove_dot_segments(path) 40 | result_segments = [] 41 | 42 | while path.length > 0 43 | if path.start_with?('../') 44 | path = path[3..-1] 45 | elsif path.start_with?('./') 46 | path = path[2..-1] 47 | elsif path.start_with?('/./') 48 | path = path[2..-1] 49 | elsif path == '/.' 50 | path = '/' 51 | elsif path.start_with?('/../') 52 | path = path[3..-1] 53 | result_segments.pop if result_segments.length > 0 54 | elsif path == '/..' 55 | path = '/' 56 | result_segments.pop if result_segments.length > 0 57 | elsif path == '..' or path == '.' 58 | path = '' 59 | else 60 | i = 0 61 | i = 1 if path[0].chr == '/' 62 | i = path.index('/', i) 63 | i = path.length if i.nil? 64 | result_segments << path[0...i] 65 | path = path[i..-1] 66 | end 67 | end 68 | 69 | return result_segments.join('') 70 | end 71 | end 72 | 73 | end 74 | -------------------------------------------------------------------------------- /examples/active_record_openid_store/README: -------------------------------------------------------------------------------- 1 | =Active Record OpenID Store Plugin 2 | 3 | A store is required by an OpenID server and optionally by the consumer 4 | to store associations, nonces, and auth key information across 5 | requests and processes. If rails is distributed across several 6 | machines, they must must all have access to the same OpenID store 7 | data, so the FilesystemStore won't do. 8 | 9 | This directory contains a plugin for connecting your 10 | OpenID enabled rails app to an ActiveRecord based OpenID store. 11 | 12 | ==Install 13 | 14 | 1) Copy this directory and all it's contents into your 15 | RAILS_ROOT/vendor/plugins directory. You structure should look like 16 | this: 17 | 18 | RAILS_ROOT/vendor/plugins/active_record_openid_store/ 19 | 20 | 2) Copy the migration, XXX_add_open_id_store_to_db.rb to your 21 | RAILS_ROOT/db/migrate directory. Rename the XXX portion of the 22 | file to next sequential migration number. 23 | 24 | 3) Run the migration: 25 | 26 | rake migrate 27 | 28 | 4) Change your app to use the ActiveRecordOpenIDStore: 29 | 30 | store = ActiveRecordOpenIDStore.new 31 | consumer = OpenID::Consumer.new(session, store) 32 | 33 | 5) That's it! All your OpenID state will now be stored in the database. 34 | 35 | ==Upgrade 36 | 37 | If you are upgrading from the 1.x ActiveRecord store, replace your old 38 | RAILS_ROOT/vendor/plugins/active_record_openid_store/ directory with 39 | the new one and run the migration XXX_upgrade_open_id_store.rb. 40 | 41 | ==What about garbage collection? 42 | 43 | You may garbage collect unused nonces and expired associations using 44 | the gc instance method of ActiveRecordOpenIDStore. Hook it up to a 45 | task in your app's Rakefile like so: 46 | 47 | desc 'GC OpenID store, deleting expired nonces and associations' 48 | task :gc_openid_store => :environment do 49 | require 'openid_ar_store' 50 | nonces, associations = ActiveRecordStore.new.cleanup 51 | puts "Deleted #{nonces} nonces, #{associations} associations" 52 | end 53 | 54 | Run it by typing: 55 | 56 | rake gc_openid_store 57 | 58 | 59 | ==Questions? 60 | Contact Dag Arneson: dag at janrain dot com 61 | -------------------------------------------------------------------------------- /lib/openid/store/nonce.rb: -------------------------------------------------------------------------------- 1 | require 'openid/cryptutil' 2 | require 'date' 3 | require 'time' 4 | 5 | module OpenID 6 | module Nonce 7 | DEFAULT_SKEW = 60*60*5 8 | TIME_FMT = '%Y-%m-%dT%H:%M:%SZ' 9 | TIME_STR_LEN = '0000-00-00T00:00:00Z'.size 10 | @@NONCE_CHRS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 11 | TIME_VALIDATOR = /\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/ 12 | 13 | @skew = DEFAULT_SKEW 14 | 15 | # The allowed nonce time skew in seconds. Defaults to 5 hours. 16 | # Used for checking nonce validity, and by stores' cleanup methods. 17 | def Nonce.skew 18 | @skew 19 | end 20 | 21 | def Nonce.skew=(new_skew) 22 | @skew = new_skew 23 | end 24 | 25 | # Extract timestamp from a nonce string 26 | def Nonce.split_nonce(nonce_str) 27 | timestamp_str = nonce_str[0...TIME_STR_LEN] 28 | raise ArgumentError if timestamp_str.size < TIME_STR_LEN 29 | raise ArgumentError unless timestamp_str.match(TIME_VALIDATOR) 30 | ts = Time.parse(timestamp_str).to_i 31 | raise ArgumentError if ts < 0 32 | return ts, nonce_str[TIME_STR_LEN..-1] 33 | end 34 | 35 | # Is the timestamp that is part of the specified nonce string 36 | # within the allowed clock-skew of the current time? 37 | def Nonce.check_timestamp(nonce_str, allowed_skew=nil, now=nil) 38 | allowed_skew = skew if allowed_skew.nil? 39 | begin 40 | stamp, _ = split_nonce(nonce_str) 41 | rescue ArgumentError # bad timestamp 42 | return false 43 | end 44 | now = Time.now.to_i unless now 45 | 46 | # times before this are too old 47 | past = now - allowed_skew 48 | 49 | # times newer than this are too far in the future 50 | future = now + allowed_skew 51 | 52 | return (past <= stamp and stamp <= future) 53 | end 54 | 55 | # generate a nonce with the specified timestamp (defaults to now) 56 | def Nonce.mk_nonce(time = nil) 57 | salt = CryptUtil::random_string(6, @@NONCE_CHRS) 58 | if time.nil? 59 | t = Time.now.getutc 60 | else 61 | t = Time.at(time).getutc 62 | end 63 | time_str = t.strftime(TIME_FMT) 64 | return time_str + salt 65 | end 66 | 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /test/test_responses.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | require "openid/consumer/discovery" 3 | require "openid/consumer/responses" 4 | 5 | module OpenID 6 | class Consumer 7 | module TestResponses 8 | class TestSuccessResponse < Minitest::Test 9 | def setup 10 | @endpoint = OpenIDServiceEndpoint.new 11 | @endpoint.claimed_id = 'identity_url' 12 | end 13 | 14 | def test_extension_response 15 | q = { 16 | 'ns.sreg' => 'urn:sreg', 17 | 'ns.unittest' => 'urn:unittest', 18 | 'unittest.one' => '1', 19 | 'unittest.two' => '2', 20 | 'sreg.nickname' => 'j3h', 21 | 'return_to' => 'return_to', 22 | } 23 | signed_list = q.keys.map { |k| 'openid.' + k } 24 | msg = Message.from_openid_args(q) 25 | resp = SuccessResponse.new(@endpoint, msg, signed_list) 26 | utargs = resp.extension_response('urn:unittest', false) 27 | assert_equal(utargs, {'one' => '1', 'two' => '2'}) 28 | sregargs = resp.extension_response('urn:sreg', false) 29 | assert_equal(sregargs, {'nickname' => 'j3h'}) 30 | end 31 | 32 | def test_extension_response_signed 33 | args = { 34 | 'ns.sreg' => 'urn:sreg', 35 | 'ns.unittest' => 'urn:unittest', 36 | 'unittest.one' => '1', 37 | 'unittest.two' => '2', 38 | 'sreg.nickname' => 'j3h', 39 | 'sreg.dob' => 'yesterday', 40 | 'return_to' => 'return_to', 41 | 'signed' => 'sreg.nickname,unittest.one,sreg.dob', 42 | } 43 | 44 | signed_list = ['openid.sreg.nickname', 45 | 'openid.unittest.one', 46 | 'openid.sreg.dob',] 47 | 48 | msg = Message.from_openid_args(args) 49 | resp = SuccessResponse.new(@endpoint, msg, signed_list) 50 | 51 | # All args in this NS are signed, so expect all. 52 | sregargs = resp.extension_response('urn:sreg', true) 53 | assert_equal(sregargs, {'nickname' => 'j3h', 'dob' => 'yesterday'}) 54 | 55 | # Not all args in this NS are signed, so expect nil when 56 | # asking for them. 57 | utargs = resp.extension_response('urn:unittest', true) 58 | assert_nil(utargs) 59 | end 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/openid/store/memory.rb: -------------------------------------------------------------------------------- 1 | require 'openid/store/interface' 2 | module OpenID 3 | module Store 4 | # An in-memory implementation of Store. This class is mainly used 5 | # for testing, though it may be useful for long-running single 6 | # process apps. Note that this store is NOT thread-safe. 7 | # 8 | # You should probably be looking at OpenID::Store::Filesystem 9 | class Memory < Interface 10 | 11 | def initialize 12 | @associations = Hash.new { |hash, key| hash[key] = {} } 13 | @nonces = {} 14 | end 15 | 16 | def store_association(server_url, assoc) 17 | assocs = @associations[server_url] 18 | @associations[server_url] = assocs.merge({assoc.handle => deepcopy(assoc)}) 19 | end 20 | 21 | def get_association(server_url, handle=nil) 22 | assocs = @associations[server_url] 23 | assoc = nil 24 | if handle 25 | assoc = assocs[handle] 26 | else 27 | assoc = assocs.values.sort{|a,b| a.issued <=> b.issued}[-1] 28 | end 29 | 30 | return assoc 31 | end 32 | 33 | def remove_association(server_url, handle) 34 | assocs = @associations[server_url] 35 | if assocs.delete(handle) 36 | return true 37 | else 38 | return false 39 | end 40 | end 41 | 42 | def use_nonce(server_url, timestamp, salt) 43 | return false if (timestamp - Time.now.to_i).abs > Nonce.skew 44 | nonce = [server_url, timestamp, salt].join('') 45 | return false if @nonces[nonce] 46 | @nonces[nonce] = timestamp 47 | return true 48 | end 49 | 50 | def cleanup_associations 51 | count = 0 52 | @associations.each{|server_url, assocs| 53 | assocs.each{|handle, assoc| 54 | if assoc.expires_in == 0 55 | assocs.delete(handle) 56 | count += 1 57 | end 58 | } 59 | } 60 | return count 61 | end 62 | 63 | def cleanup_nonces 64 | count = 0 65 | now = Time.now.to_i 66 | @nonces.each{|nonce, timestamp| 67 | if (timestamp - now).abs > Nonce.skew 68 | @nonces.delete(nonce) 69 | count += 1 70 | end 71 | } 72 | return count 73 | end 74 | 75 | protected 76 | 77 | def deepcopy(o) 78 | Marshal.load(Marshal.dump(o)) 79 | end 80 | 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /test/test_parsehtml.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | require "testutil" 3 | require "openid/yadis/parsehtml" 4 | 5 | module OpenID 6 | class ParseHTMLTestCase < Minitest::Test 7 | include OpenID::TestDataMixin 8 | 9 | def test_parsehtml 10 | reserved_values = ['None', 'EOF'] 11 | chunks = read_data_file('test1-parsehtml.txt', false).split("\f\n") 12 | 13 | chunks.each{|c| 14 | expected, html = c.split("\n", 2) 15 | found = Yadis::html_yadis_location(html) 16 | 17 | assert(!reserved_values.member?(found)) 18 | 19 | # this case is a little hard to detect and the distinction 20 | # seems unimportant 21 | expected = "None" if expected == "EOF" 22 | 23 | found = "None" if found.nil? 24 | assert_equal(expected, found, html.split("\n",2)[0]) 25 | } 26 | end 27 | end 28 | 29 | # the HTML tokenizer test 30 | class TC_TestHTMLTokenizer < Minitest::Test 31 | def test_bad_link 32 | toke = HTMLTokenizer.new("") 33 | assert("http://bad.com/link" == toke.getTag("a").attr_hash['href']) 34 | end 35 | 36 | def test_namespace 37 | toke = HTMLTokenizer.new("
59 | This is the paragraph, it contains
60 | links,
61 |
. Ok, here is some more text and
64 | another link.
65 |
Blah blah blah blah blah blah blah
13 | 14 | 15 | 16 | header 17 | Status: 200 OK 18 | Content-Type: text/html 19 | YADIS_HEADER: URL_BASE/xrds 20 | 21 | 22 | 23 |Blah blah blah blah blah blah blah
28 | 29 | 30 | xrds 31 | Status: 200 OK 32 | Content-Type: application/xrds+xml 33 | 34 |Blah blah blah blah blah blah blah
101 | 102 | 103 | 404_server_response 104 | Status: 404 Not Found 105 | 106 | EEk! 107 | 108 | 500_server_response 109 | Status: 500 Server error 110 | 111 | EEk! 112 | 113 | 201_server_response 114 | Status: 201 Created 115 | 116 | EEk! 117 | 118 | 404_with_header 119 | Status: 404 Not Found 120 | YADIS_HEADER: URL_BASE/xrds 121 | 122 | EEk! 123 | 124 | 404_with_meta 125 | Status: 404 Not Found 126 | Content-Type: text/html 127 | 128 | 129 | 130 | 131 |Blah blah blah blah blah blah blah
136 | 137 | 138 | -------------------------------------------------------------------------------- /lib/openid/extensions/oauth.rb: -------------------------------------------------------------------------------- 1 | # An implementation of the OpenID OAuth Extension 2 | # Extension 1.0 3 | # see: http://openid.net/specs/ 4 | 5 | require 'openid/extension' 6 | 7 | module OpenID 8 | 9 | module OAuth 10 | NS_URI = "http://specs.openid.net/extensions/oauth/1.0" 11 | # An OAuth token request, sent from a relying 12 | # party to a provider 13 | class Request < Extension 14 | attr_accessor :consumer, :scope, :ns_alias, :ns_uri 15 | def initialize(consumer=nil, scope=nil) 16 | @ns_alias = 'oauth' 17 | @ns_uri = NS_URI 18 | @consumer = consumer 19 | @scope = scope 20 | end 21 | 22 | 23 | def get_extension_args 24 | ns_args = {} 25 | ns_args['consumer'] = @consumer if @consumer 26 | ns_args['scope'] = @scope if @scope 27 | return ns_args 28 | end 29 | 30 | # Instantiate a Request object from the arguments in a 31 | # checkid_* OpenID message 32 | # return nil if the extension was not requested. 33 | def self.from_openid_request(oid_req) 34 | oauth_req = new 35 | args = oid_req.message.get_args(NS_URI) 36 | if args == {} 37 | return nil 38 | end 39 | oauth_req.parse_extension_args(args) 40 | return oauth_req 41 | end 42 | 43 | # Set the state of this request to be that expressed in these 44 | # OAuth arguments 45 | def parse_extension_args(args) 46 | @consumer = args["consumer"] 47 | @scope = args["scope"] 48 | end 49 | 50 | end 51 | 52 | # A OAuth request token response, sent from a provider 53 | # to a relying party 54 | class Response < Extension 55 | attr_accessor :request_token, :scope 56 | def initialize(request_token=nil, scope=nil) 57 | @ns_alias = 'oauth' 58 | @ns_uri = NS_URI 59 | @request_token = request_token 60 | @scope = scope 61 | end 62 | 63 | # Create a Response object from an OpenID::Consumer::SuccessResponse 64 | def self.from_success_response(success_response) 65 | args = success_response.get_signed_ns(NS_URI) 66 | return nil if args.nil? 67 | oauth_resp = new 68 | oauth_resp.parse_extension_args(args) 69 | return oauth_resp 70 | end 71 | 72 | # parse the oauth request arguments into the 73 | # internal state of this object 74 | # if strict is specified, raise an exception when bad data is 75 | # encountered 76 | def parse_extension_args(args, strict=false) 77 | @request_token = args["request_token"] 78 | @scope = args["scope"] 79 | end 80 | 81 | def get_extension_args 82 | ns_args = {} 83 | ns_args['request_token'] = @request_token if @request_token 84 | ns_args['scope'] = @scope if @scope 85 | return ns_args 86 | end 87 | 88 | end 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /lib/openid/yadis/xri.rb: -------------------------------------------------------------------------------- 1 | require 'openid/fetchers' 2 | 3 | module OpenID 4 | module Yadis 5 | module XRI 6 | 7 | # The '(' is for cross-reference authorities, and hopefully has a 8 | # matching ')' somewhere. 9 | XRI_AUTHORITIES = ["!", "=", "@", "+", "$", "("] 10 | 11 | def self.identifier_scheme(identifier) 12 | if (!identifier.nil? and 13 | identifier.length > 0 and 14 | (identifier.match('^xri://') or 15 | XRI_AUTHORITIES.member?(identifier[0].chr))) 16 | return :xri 17 | else 18 | return :uri 19 | end 20 | end 21 | 22 | # Transform an XRI reference to an IRI reference. Note this is 23 | # not not idempotent, so do not apply this to an identifier more 24 | # than once. XRI Syntax section 2.3.1 25 | def self.to_iri_normal(xri) 26 | iri = xri.dup 27 | iri.insert(0, 'xri://') if not iri.match('^xri://') 28 | return escape_for_iri(iri) 29 | end 30 | 31 | # Note this is not not idempotent, so do not apply this more than 32 | # once. XRI Syntax section 2.3.2 33 | def self.escape_for_iri(xri) 34 | esc = xri.dup 35 | # encode all % 36 | esc.gsub!(/%/, '%25') 37 | esc.gsub!(/\((.*?)\)/) { |xref_match| 38 | xref_match.gsub(/[\/\?\#]/) { |char_match| 39 | CGI::escape(char_match) 40 | } 41 | } 42 | return esc 43 | end 44 | 45 | # Transform an XRI reference to a URI reference. Note this is not 46 | # not idempotent, so do not apply this to an identifier more than 47 | # once. XRI Syntax section 2.3.1 48 | def self.to_uri_normal(xri) 49 | return iri_to_uri(to_iri_normal(xri)) 50 | end 51 | 52 | # RFC 3987 section 3.1 53 | def self.iri_to_uri(iri) 54 | uri = iri.dup 55 | # for char in ucschar or iprivate 56 | # convert each char to %HH%HH%HH (as many %HH as octets) 57 | return uri 58 | end 59 | 60 | def self.provider_is_authoritative(provider_id, canonical_id) 61 | lastbang = canonical_id.rindex('!') 62 | return false unless lastbang 63 | parent = canonical_id[0...lastbang] 64 | return parent == provider_id 65 | end 66 | 67 | def self.root_authority(xri) 68 | xri = xri[6..-1] if xri.index('xri://') == 0 69 | authority = xri.split('/', 2)[0] 70 | if authority[0].chr == '(' 71 | root = authority[0...authority.index(')')+1] 72 | elsif XRI_AUTHORITIES.member?(authority[0].chr) 73 | root = authority[0].chr 74 | else 75 | root = authority.split(/[!*]/)[0] 76 | end 77 | 78 | self.make_xri(root) 79 | end 80 | 81 | def self.make_xri(xri) 82 | if xri.index('xri://') != 0 83 | xri = 'xri://' + xri 84 | end 85 | return xri 86 | end 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /test/test_ui.rb: -------------------------------------------------------------------------------- 1 | require 'openid/extensions/ui' 2 | require 'openid/message' 3 | require 'openid/server' 4 | require 'minitest/autorun' 5 | 6 | module OpenID 7 | module UITest 8 | class UIRequestTestCase < Minitest::Test 9 | 10 | def setup 11 | @req = UI::Request.new 12 | end 13 | 14 | def test_construct 15 | assert_nil @req.mode 16 | assert_nil @req.icon 17 | assert_nil @req.lang 18 | assert_equal 'ui', @req.ns_alias 19 | 20 | req2 = UI::Request.new("popup", true, "ja-JP") 21 | assert_equal "popup", req2.mode 22 | assert_equal true, req2.icon 23 | assert_equal "ja-JP", req2.lang 24 | end 25 | 26 | def test_add_mode 27 | @req.mode = "popup" 28 | assert_equal "popup", @req.mode 29 | end 30 | 31 | def test_add_icon 32 | @req.icon = true 33 | assert_equal true, @req.icon 34 | end 35 | 36 | def test_add_lang 37 | @req.lang = "ja-JP" 38 | assert_equal "ja-JP", @req.lang 39 | end 40 | 41 | def test_get_extension_args 42 | assert_equal({}, @req.get_extension_args) 43 | @req.mode = "popup" 44 | assert_equal({'mode' => 'popup'}, @req.get_extension_args) 45 | @req.icon = true 46 | assert_equal({'mode' => 'popup', 'icon' => true}, @req.get_extension_args) 47 | @req.lang = "ja-JP" 48 | assert_equal({'mode' => 'popup', 'icon' => true, 'lang' => 'ja-JP'}, @req.get_extension_args) 49 | end 50 | 51 | def test_parse_extension_args 52 | args = {'mode' => 'popup', 'icon' => true, 'lang' => 'ja-JP'} 53 | @req.parse_extension_args args 54 | assert_equal "popup", @req.mode 55 | assert_equal true, @req.icon 56 | assert_equal "ja-JP", @req.lang 57 | end 58 | 59 | def test_parse_extension_args_empty 60 | @req.parse_extension_args({}) 61 | assert_nil @req.mode 62 | assert_nil @req.icon 63 | assert_nil @req.lang 64 | end 65 | 66 | def test_from_openid_request 67 | openid_req_msg = Message.from_openid_args( 68 | 'mode' => 'checkid_setup', 69 | 'ns' => OPENID2_NS, 70 | 'ns.ui' => UI::NS_URI, 71 | 'ui.mode' => 'popup', 72 | 'ui.icon' => true, 73 | 'ui.lang' => 'ja-JP' 74 | ) 75 | oid_req = Server::OpenIDRequest.new 76 | oid_req.message = openid_req_msg 77 | req = UI::Request.from_openid_request oid_req 78 | assert_equal "popup", req.mode 79 | assert_equal true, req.icon 80 | assert_equal "ja-JP", req.lang 81 | end 82 | 83 | def test_from_openid_request_no_ui_params 84 | message = Message.new 85 | openid_req = Server::OpenIDRequest.new 86 | openid_req.message = message 87 | ui_req = UI::Request.from_openid_request openid_req 88 | assert ui_req.nil? 89 | end 90 | 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /examples/rails_openid/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | if defined?(Bundler) 6 | # If you precompile assets before deploying to production, use this line 7 | Bundler.require(*Rails.groups(:assets => %w(development test))) 8 | # If you want your assets lazily compiled in production, use this line 9 | # Bundler.require(:default, :assets, Rails.env) 10 | end 11 | 12 | module RailsOpenid 13 | class Application < Rails::Application 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | # Custom directories with classes and modules you want to be autoloadable. 19 | # config.autoload_paths += %W(#{config.root}/extras) 20 | 21 | # Only load the plugins named here, in the order given (default is alphabetical). 22 | # :all can be used as a placeholder for all plugins not explicitly named. 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 24 | 25 | # Activate observers that should always be running. 26 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 27 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 30 | # config.time_zone = 'Central Time (US & Canada)' 31 | 32 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 33 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 34 | # config.i18n.default_locale = :de 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable escaping HTML in JSON. 43 | config.active_support.escape_html_entities_in_json = true 44 | 45 | # Use SQL instead of Active Record's schema dumper when creating the database. 46 | # This is necessary if your schema can't be completely dumped by the schema dumper, 47 | # like if you have constraints or database-specific column types 48 | # config.active_record.schema_format = :sql 49 | 50 | # Enforce whitelist mode for mass assignment. 51 | # This will create an empty whitelist of attributes available for mass-assignment for all models 52 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible 53 | # parameters by using an attr_accessible or attr_protected declaration. 54 | config.active_record.whitelist_attributes = true 55 | 56 | # Enable the asset pipeline 57 | config.assets.enabled = true 58 | 59 | # Version of your assets, change this if you want to expire all your assets 60 | config.assets.version = '1.0' 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/openid/dh.rb: -------------------------------------------------------------------------------- 1 | require "openid/util" 2 | require "openid/cryptutil" 3 | 4 | module OpenID 5 | 6 | # Encapsulates a Diffie-Hellman key exchange. This class is used 7 | # internally by both the consumer and server objects. 8 | # 9 | # Read more about Diffie-Hellman on wikipedia: 10 | # http://en.wikipedia.org/wiki/Diffie-Hellman 11 | 12 | class DiffieHellman 13 | 14 | # From the OpenID specification 15 | @@default_mod = 155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443 16 | @@default_gen = 2 17 | 18 | attr_reader :modulus, :generator, :public 19 | 20 | # A new DiffieHellman object, using the modulus and generator from 21 | # the OpenID specification 22 | def DiffieHellman.from_defaults 23 | DiffieHellman.new(@@default_mod, @@default_gen) 24 | end 25 | 26 | def initialize(modulus=nil, generator=nil, priv=nil) 27 | @modulus = modulus.nil? ? @@default_mod : modulus 28 | @generator = generator.nil? ? @@default_gen : generator 29 | set_private(priv.nil? ? OpenID::CryptUtil.rand(@modulus-2) + 1 : priv) 30 | end 31 | 32 | def get_shared_secret(composite) 33 | DiffieHellman.powermod(composite, @private, @modulus) 34 | end 35 | 36 | def xor_secret(algorithm, composite, secret) 37 | dh_shared = get_shared_secret(composite) 38 | packed_dh_shared = OpenID::CryptUtil.num_to_binary(dh_shared) 39 | hashed_dh_shared = algorithm.call(packed_dh_shared) 40 | return DiffieHellman.strxor(secret, hashed_dh_shared) 41 | end 42 | 43 | def using_default_values? 44 | @generator == @@default_gen && @modulus == @@default_mod 45 | end 46 | 47 | private 48 | def set_private(priv) 49 | @private = priv 50 | @public = DiffieHellman.powermod(@generator, @private, @modulus) 51 | end 52 | 53 | def DiffieHellman.strxor(s, t) 54 | if s.length != t.length 55 | raise ArgumentError, "strxor: lengths don't match. " + 56 | "Inputs were #{s.inspect} and #{t.inspect}" 57 | end 58 | 59 | if String.method_defined? :bytes 60 | s.bytes.to_a.zip(t.bytes.to_a).map{|sb,tb| sb^tb}.pack('C*') 61 | else 62 | indices = 0...(s.length) 63 | chrs = indices.collect {|i| (s[i]^t[i]).chr} 64 | chrs.join("") 65 | end 66 | end 67 | 68 | # This code is taken from this post: 69 | #