entp-ruby-openid 2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. data/CHANGELOG +215 -0
  2. data/INSTALL +47 -0
  3. data/LICENSE +210 -0
  4. data/NOTICE +2 -0
  5. data/README +85 -0
  6. data/UPGRADE +127 -0
  7. data/admin/runtests.rb +45 -0
  8. data/examples/README +32 -0
  9. data/examples/active_record_openid_store/README +58 -0
  10. data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +24 -0
  11. data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
  12. data/examples/active_record_openid_store/init.rb +8 -0
  13. data/examples/active_record_openid_store/lib/association.rb +10 -0
  14. data/examples/active_record_openid_store/lib/nonce.rb +3 -0
  15. data/examples/active_record_openid_store/lib/open_id_setting.rb +4 -0
  16. data/examples/active_record_openid_store/lib/openid_ar_store.rb +57 -0
  17. data/examples/active_record_openid_store/test/store_test.rb +212 -0
  18. data/examples/discover +49 -0
  19. data/examples/rails_openid/README +153 -0
  20. data/examples/rails_openid/Rakefile +10 -0
  21. data/examples/rails_openid/app/controllers/application.rb +4 -0
  22. data/examples/rails_openid/app/controllers/consumer_controller.rb +125 -0
  23. data/examples/rails_openid/app/controllers/login_controller.rb +45 -0
  24. data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
  25. data/examples/rails_openid/app/helpers/application_helper.rb +3 -0
  26. data/examples/rails_openid/app/helpers/login_helper.rb +2 -0
  27. data/examples/rails_openid/app/helpers/server_helper.rb +9 -0
  28. data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
  29. data/examples/rails_openid/app/views/layouts/server.rhtml +68 -0
  30. data/examples/rails_openid/app/views/login/index.rhtml +56 -0
  31. data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
  32. data/examples/rails_openid/config/boot.rb +19 -0
  33. data/examples/rails_openid/config/database.yml +74 -0
  34. data/examples/rails_openid/config/environment.rb +54 -0
  35. data/examples/rails_openid/config/environments/development.rb +19 -0
  36. data/examples/rails_openid/config/environments/production.rb +19 -0
  37. data/examples/rails_openid/config/environments/test.rb +19 -0
  38. data/examples/rails_openid/config/routes.rb +24 -0
  39. data/examples/rails_openid/doc/README_FOR_APP +2 -0
  40. data/examples/rails_openid/public/404.html +8 -0
  41. data/examples/rails_openid/public/500.html +8 -0
  42. data/examples/rails_openid/public/dispatch.cgi +12 -0
  43. data/examples/rails_openid/public/dispatch.fcgi +26 -0
  44. data/examples/rails_openid/public/dispatch.rb +12 -0
  45. data/examples/rails_openid/public/favicon.ico +0 -0
  46. data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
  47. data/examples/rails_openid/public/javascripts/controls.js +750 -0
  48. data/examples/rails_openid/public/javascripts/dragdrop.js +584 -0
  49. data/examples/rails_openid/public/javascripts/effects.js +854 -0
  50. data/examples/rails_openid/public/javascripts/prototype.js +1785 -0
  51. data/examples/rails_openid/public/robots.txt +1 -0
  52. data/examples/rails_openid/script/about +3 -0
  53. data/examples/rails_openid/script/breakpointer +3 -0
  54. data/examples/rails_openid/script/console +3 -0
  55. data/examples/rails_openid/script/destroy +3 -0
  56. data/examples/rails_openid/script/generate +3 -0
  57. data/examples/rails_openid/script/performance/benchmarker +3 -0
  58. data/examples/rails_openid/script/performance/profiler +3 -0
  59. data/examples/rails_openid/script/plugin +3 -0
  60. data/examples/rails_openid/script/process/reaper +3 -0
  61. data/examples/rails_openid/script/process/spawner +3 -0
  62. data/examples/rails_openid/script/process/spinner +3 -0
  63. data/examples/rails_openid/script/runner +3 -0
  64. data/examples/rails_openid/script/server +3 -0
  65. data/examples/rails_openid/test/functional/login_controller_test.rb +18 -0
  66. data/examples/rails_openid/test/functional/server_controller_test.rb +18 -0
  67. data/examples/rails_openid/test/test_helper.rb +28 -0
  68. data/lib/hmac/hmac.rb +112 -0
  69. data/lib/hmac/sha1.rb +11 -0
  70. data/lib/hmac/sha2.rb +25 -0
  71. data/lib/openid.rb +22 -0
  72. data/lib/openid/association.rb +249 -0
  73. data/lib/openid/consumer.rb +395 -0
  74. data/lib/openid/consumer/associationmanager.rb +344 -0
  75. data/lib/openid/consumer/checkid_request.rb +186 -0
  76. data/lib/openid/consumer/discovery.rb +497 -0
  77. data/lib/openid/consumer/discovery_manager.rb +123 -0
  78. data/lib/openid/consumer/html_parse.rb +134 -0
  79. data/lib/openid/consumer/idres.rb +523 -0
  80. data/lib/openid/consumer/responses.rb +150 -0
  81. data/lib/openid/cryptutil.rb +115 -0
  82. data/lib/openid/dh.rb +89 -0
  83. data/lib/openid/extension.rb +39 -0
  84. data/lib/openid/extensions/ax.rb +539 -0
  85. data/lib/openid/extensions/oauth.rb +91 -0
  86. data/lib/openid/extensions/pape.rb +179 -0
  87. data/lib/openid/extensions/sreg.rb +277 -0
  88. data/lib/openid/extras.rb +11 -0
  89. data/lib/openid/fetchers.rb +258 -0
  90. data/lib/openid/kvform.rb +136 -0
  91. data/lib/openid/kvpost.rb +58 -0
  92. data/lib/openid/message.rb +553 -0
  93. data/lib/openid/protocolerror.rb +12 -0
  94. data/lib/openid/server.rb +1544 -0
  95. data/lib/openid/store.rb +10 -0
  96. data/lib/openid/store/filesystem.rb +272 -0
  97. data/lib/openid/store/interface.rb +75 -0
  98. data/lib/openid/store/memcache.rb +109 -0
  99. data/lib/openid/store/memory.rb +84 -0
  100. data/lib/openid/store/nonce.rb +68 -0
  101. data/lib/openid/trustroot.rb +349 -0
  102. data/lib/openid/urinorm.rb +75 -0
  103. data/lib/openid/util.rb +119 -0
  104. data/lib/openid/version.rb +3 -0
  105. data/lib/openid/yadis.rb +15 -0
  106. data/lib/openid/yadis/accept.rb +148 -0
  107. data/lib/openid/yadis/constants.rb +21 -0
  108. data/lib/openid/yadis/discovery.rb +153 -0
  109. data/lib/openid/yadis/filters.rb +205 -0
  110. data/lib/openid/yadis/htmltokenizer.rb +305 -0
  111. data/lib/openid/yadis/parsehtml.rb +45 -0
  112. data/lib/openid/yadis/services.rb +42 -0
  113. data/lib/openid/yadis/xrds.rb +155 -0
  114. data/lib/openid/yadis/xri.rb +90 -0
  115. data/lib/openid/yadis/xrires.rb +91 -0
  116. data/test/data/test_discover/openid_utf8.html +11 -0
  117. data/test/support/test_data_mixin.rb +127 -0
  118. data/test/support/test_util.rb +53 -0
  119. data/test/support/yadis_data.rb +131 -0
  120. data/test/support/yadis_data/accept.txt +124 -0
  121. data/test/support/yadis_data/dh.txt +29 -0
  122. data/test/support/yadis_data/example-xrds.xml +14 -0
  123. data/test/support/yadis_data/linkparse.txt +587 -0
  124. data/test/support/yadis_data/n2b64 +650 -0
  125. data/test/support/yadis_data/test1-discover.txt +137 -0
  126. data/test/support/yadis_data/test1-parsehtml.txt +152 -0
  127. data/test/support/yadis_data/test_discover/malformed_meta_tag.html +19 -0
  128. data/test/support/yadis_data/test_discover/openid.html +11 -0
  129. data/test/support/yadis_data/test_discover/openid2.html +11 -0
  130. data/test/support/yadis_data/test_discover/openid2_xrds.xml +12 -0
  131. data/test/support/yadis_data/test_discover/openid2_xrds_no_local_id.xml +11 -0
  132. data/test/support/yadis_data/test_discover/openid_1_and_2.html +11 -0
  133. data/test/support/yadis_data/test_discover/openid_1_and_2_xrds.xml +16 -0
  134. data/test/support/yadis_data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
  135. data/test/support/yadis_data/test_discover/openid_and_yadis.html +12 -0
  136. data/test/support/yadis_data/test_discover/openid_no_delegate.html +10 -0
  137. data/test/support/yadis_data/test_discover/openid_utf8.html +11 -0
  138. data/test/support/yadis_data/test_discover/yadis_0entries.xml +12 -0
  139. data/test/support/yadis_data/test_discover/yadis_2_bad_local_id.xml +15 -0
  140. data/test/support/yadis_data/test_discover/yadis_2entries_delegate.xml +22 -0
  141. data/test/support/yadis_data/test_discover/yadis_2entries_idp.xml +21 -0
  142. data/test/support/yadis_data/test_discover/yadis_another_delegate.xml +14 -0
  143. data/test/support/yadis_data/test_discover/yadis_idp.xml +12 -0
  144. data/test/support/yadis_data/test_discover/yadis_idp_delegate.xml +13 -0
  145. data/test/support/yadis_data/test_discover/yadis_no_delegate.xml +11 -0
  146. data/test/support/yadis_data/test_xrds/=j3h.2007.11.14.xrds +25 -0
  147. data/test/support/yadis_data/test_xrds/README +12 -0
  148. data/test/support/yadis_data/test_xrds/delegated-20060809-r1.xrds +34 -0
  149. data/test/support/yadis_data/test_xrds/delegated-20060809-r2.xrds +34 -0
  150. data/test/support/yadis_data/test_xrds/delegated-20060809.xrds +34 -0
  151. data/test/support/yadis_data/test_xrds/no-xrd.xml +7 -0
  152. data/test/support/yadis_data/test_xrds/not-xrds.xml +2 -0
  153. data/test/support/yadis_data/test_xrds/prefixsometimes.xrds +34 -0
  154. data/test/support/yadis_data/test_xrds/ref.xrds +109 -0
  155. data/test/support/yadis_data/test_xrds/sometimesprefix.xrds +34 -0
  156. data/test/support/yadis_data/test_xrds/spoof1.xrds +25 -0
  157. data/test/support/yadis_data/test_xrds/spoof2.xrds +25 -0
  158. data/test/support/yadis_data/test_xrds/spoof3.xrds +37 -0
  159. data/test/support/yadis_data/test_xrds/status222.xrds +9 -0
  160. data/test/support/yadis_data/test_xrds/subsegments.xrds +58 -0
  161. data/test/support/yadis_data/test_xrds/valid-populated-xrds.xml +39 -0
  162. data/test/support/yadis_data/trustroot.txt +153 -0
  163. data/test/support/yadis_data/urinorm.txt +79 -0
  164. data/test/test_accept.rb +170 -0
  165. data/test/test_association.rb +268 -0
  166. data/test/test_associationmanager.rb +918 -0
  167. data/test/test_ax.rb +690 -0
  168. data/test/test_checkid_request.rb +293 -0
  169. data/test/test_consumer.rb +260 -0
  170. data/test/test_cryptutil.rb +119 -0
  171. data/test/test_dh.rb +85 -0
  172. data/test/test_discover.rb +848 -0
  173. data/test/test_discovery_manager.rb +259 -0
  174. data/test/test_extension.rb +46 -0
  175. data/test/test_extras.rb +35 -0
  176. data/test/test_fetchers.rb +554 -0
  177. data/test/test_filters.rb +269 -0
  178. data/test/test_helper.rb +4 -0
  179. data/test/test_idres.rb +961 -0
  180. data/test/test_kvform.rb +164 -0
  181. data/test/test_kvpost.rb +64 -0
  182. data/test/test_linkparse.rb +100 -0
  183. data/test/test_message.rb +1115 -0
  184. data/test/test_nonce.rb +89 -0
  185. data/test/test_oauth.rb +176 -0
  186. data/test/test_openid_yadis.rb +177 -0
  187. data/test/test_pape.rb +248 -0
  188. data/test/test_parsehtml.rb +79 -0
  189. data/test/test_responses.rb +63 -0
  190. data/test/test_server.rb +2455 -0
  191. data/test/test_sreg.rb +479 -0
  192. data/test/test_stores.rb +292 -0
  193. data/test/test_trustroot.rb +111 -0
  194. data/test/test_urinorm.rb +34 -0
  195. data/test/test_util.rb +145 -0
  196. data/test/test_xrds.rb +167 -0
  197. data/test/test_xri.rb +48 -0
  198. data/test/test_xrires.rb +67 -0
  199. data/test/test_yadis_discovery.rb +218 -0
  200. metadata +268 -0
@@ -0,0 +1,75 @@
1
+ require 'uri'
2
+
3
+ require "openid/extras"
4
+
5
+ module OpenID
6
+
7
+ module URINorm
8
+ public
9
+ def URINorm.urinorm(uri)
10
+ uri = URI.parse(uri)
11
+
12
+ raise URI::InvalidURIError.new('no scheme') unless uri.scheme
13
+ uri.scheme = uri.scheme.downcase
14
+ unless ['http','https'].member?(uri.scheme)
15
+ raise URI::InvalidURIError.new('Not an HTTP or HTTPS URI')
16
+ end
17
+
18
+ raise URI::InvalidURIError.new('no host') unless uri.host
19
+ uri.host = uri.host.downcase
20
+
21
+ uri.path = remove_dot_segments(uri.path)
22
+ uri.path = '/' if uri.path.length == 0
23
+
24
+ uri = uri.normalize.to_s
25
+ uri = uri.gsub(PERCENT_ESCAPE_RE) {
26
+ sub = $&[1..2].to_i(16).chr
27
+ reserved(sub) ? $&.upcase : sub
28
+ }
29
+
30
+ return uri
31
+ end
32
+
33
+ private
34
+ RESERVED_RE = /[A-Za-z0-9._~-]/
35
+ PERCENT_ESCAPE_RE = /%[0-9a-zA-Z]{2}/
36
+
37
+ def URINorm.reserved(chr)
38
+ not RESERVED_RE =~ chr
39
+ end
40
+
41
+ def URINorm.remove_dot_segments(path)
42
+ result_segments = []
43
+
44
+ while path.length > 0
45
+ if path.starts_with?('../')
46
+ path = path[3..-1]
47
+ elsif path.starts_with?('./')
48
+ path = path[2..-1]
49
+ elsif path.starts_with?('/./')
50
+ path = path[2..-1]
51
+ elsif path == '/.'
52
+ path = '/'
53
+ elsif path.starts_with?('/../')
54
+ path = path[3..-1]
55
+ result_segments.pop if result_segments.length > 0
56
+ elsif path == '/..'
57
+ path = '/'
58
+ result_segments.pop if result_segments.length > 0
59
+ elsif path == '..' or path == '.'
60
+ path = ''
61
+ else
62
+ i = 0
63
+ i = 1 if path[0].chr == '/'
64
+ i = path.index('/', i)
65
+ i = path.length if i.nil?
66
+ result_segments << path[0...i]
67
+ path = path[i..-1]
68
+ end
69
+ end
70
+
71
+ return result_segments.join('')
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,119 @@
1
+ require "cgi"
2
+ require "uri"
3
+ require "logger"
4
+
5
+ require "openid/extras"
6
+
7
+ # See OpenID::Consumer or OpenID::Server modules, as well as the store classes
8
+ module OpenID
9
+ class AssertionError < Exception
10
+ end
11
+
12
+ # Exceptions that are raised by the library are subclasses of this
13
+ # exception type, so if you want to catch all exceptions raised by
14
+ # the library, you can catch OpenIDError
15
+ class OpenIDError < StandardError
16
+ def initialize(*msgs)
17
+ super(msgs.join(', '))
18
+ end
19
+ end
20
+
21
+ module Util
22
+
23
+ BASE64_CHARS = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' \
24
+ 'abcdefghijklmnopqrstuvwxyz0123456789+/')
25
+ BASE64_RE = Regexp.compile("
26
+ \\A
27
+ ([#{BASE64_CHARS}]{4})*
28
+ ([#{BASE64_CHARS}]{2}==|
29
+ [#{BASE64_CHARS}]{3}=)?
30
+ \\Z", Regexp::EXTENDED)
31
+
32
+ def Util.assert(value, message=nil)
33
+ if not value
34
+ raise AssertionError, message or value
35
+ end
36
+ end
37
+
38
+ def Util.to_base64(s)
39
+ [s].pack('m').gsub("\n", "")
40
+ end
41
+
42
+ def Util.from_base64(s)
43
+ without_newlines = s.gsub(/[\r\n]+/, '')
44
+ if !BASE64_RE.match(without_newlines)
45
+ raise ArgumentError, "Malformed input: #{s.inspect}"
46
+ end
47
+ without_newlines.unpack('m').first
48
+ end
49
+
50
+ def Util.urlencode(args)
51
+ a = []
52
+ args.each do |key, val|
53
+ val = '' unless val
54
+ a << (CGI::escape(key) + "=" + CGI::escape(val))
55
+ end
56
+ a.join("&")
57
+ end
58
+
59
+ def Util.parse_query(qs)
60
+ query = {}
61
+ CGI::parse(qs).each {|k,v| query[k] = v[0]}
62
+ return query
63
+ end
64
+
65
+ def Util.append_args(url, args)
66
+ url = url.dup
67
+ return url if args.length == 0
68
+
69
+ if args.respond_to?('each_pair')
70
+ args = args.sort
71
+ end
72
+
73
+ url << (url.include?("?") ? "&" : "?")
74
+ url << Util.urlencode(args)
75
+ end
76
+
77
+ @@logger = Logger.new(STDERR)
78
+ @@logger.progname = "OpenID"
79
+
80
+ def Util.logger=(logger)
81
+ @@logger = logger
82
+ end
83
+
84
+ def Util.logger
85
+ @@logger
86
+ end
87
+
88
+ # change the message below to do whatever you like for logging
89
+ def Util.log(message)
90
+ logger.info(message)
91
+ end
92
+
93
+ def Util.auto_submit_html(form, title='OpenID transaction in progress')
94
+ return "
95
+ <html>
96
+ <head>
97
+ <title>#{title}</title>
98
+ </head>
99
+ <body onload='document.forms[0].submit();'>
100
+ #{form}
101
+ <script>
102
+ var elements = document.forms[0].elements;
103
+ for (var i = 0; i < elements.length; i++) {
104
+ elements[i].style.display = \"none\";
105
+ }
106
+ </script>
107
+ </body>
108
+ </html>
109
+ "
110
+ end
111
+
112
+ ESCAPE_TABLE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#039;' }
113
+ # Modified from ERb's html_encode
114
+ def Util.html_encode(s)
115
+ s.to_s.gsub(/[&<>"']/) {|s| ESCAPE_TABLE[s] }
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,3 @@
1
+ module OpenID
2
+ VERSION = "2.1.9"
3
+ end
@@ -0,0 +1,15 @@
1
+ require 'openid/yadis/accept'
2
+ require 'openid/yadis/constants'
3
+ require 'openid/yadis/discovery'
4
+ require 'openid/yadis/filters'
5
+ require 'openid/yadis/htmltokenizer'
6
+ require 'openid/yadis/parsehtml'
7
+ require 'openid/yadis/services'
8
+ require 'openid/yadis/xrds'
9
+ require 'openid/yadis/xri'
10
+ require 'openid/yadis/xrires'
11
+
12
+ module OpenID
13
+ module Yadis
14
+ end
15
+ end
@@ -0,0 +1,148 @@
1
+ module OpenID
2
+
3
+ module Yadis
4
+
5
+ # Generate an accept header value
6
+ #
7
+ # [str or (str, float)] -> str
8
+ def self.generate_accept_header(*elements)
9
+ parts = []
10
+ elements.each { |element|
11
+ if element.is_a?(String)
12
+ qs = "1.0"
13
+ mtype = element
14
+ else
15
+ mtype, q = element
16
+ q = q.to_f
17
+ if q > 1 or q <= 0
18
+ raise ArgumentError.new("Invalid preference factor: #{q}")
19
+ end
20
+ qs = sprintf("%0.1f", q)
21
+ end
22
+
23
+ parts << [qs, mtype]
24
+ }
25
+
26
+ parts.sort!
27
+ chunks = []
28
+ parts.each { |q, mtype|
29
+ if q == '1.0'
30
+ chunks << mtype
31
+ else
32
+ chunks << sprintf("%s; q=%s", mtype, q)
33
+ end
34
+ }
35
+
36
+ return chunks.join(', ')
37
+ end
38
+
39
+ def self.parse_accept_header(value)
40
+ # Parse an accept header, ignoring any accept-extensions
41
+ #
42
+ # returns a list of tuples containing main MIME type, MIME
43
+ # subtype, and quality markdown.
44
+ #
45
+ # str -> [(str, str, float)]
46
+ chunks = value.split(',', -1).collect { |v| v.strip }
47
+ accept = []
48
+ chunks.each { |chunk|
49
+ parts = chunk.split(";", -1).collect { |s| s.strip }
50
+
51
+ mtype = parts.shift
52
+ if mtype.index('/').nil?
53
+ # This is not a MIME type, so ignore the bad data
54
+ next
55
+ end
56
+
57
+ main, sub = mtype.split('/', 2)
58
+
59
+ q = nil
60
+ parts.each { |ext|
61
+ if !ext.index('=').nil?
62
+ k, v = ext.split('=', 2)
63
+ if k == 'q'
64
+ q = v.to_f
65
+ end
66
+ end
67
+ }
68
+
69
+ q = 1.0 if q.nil?
70
+
71
+ accept << [q, main, sub]
72
+ }
73
+
74
+ accept.sort!
75
+ accept.reverse!
76
+
77
+ return accept.collect { |q, main, sub| [main, sub, q] }
78
+ end
79
+
80
+ def self.match_types(accept_types, have_types)
81
+ # Given the result of parsing an Accept: header, and the
82
+ # available MIME types, return the acceptable types with their
83
+ # quality markdowns.
84
+ #
85
+ # For example:
86
+ #
87
+ # >>> acceptable = parse_accept_header('text/html, text/plain; q=0.5')
88
+ # >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg'])
89
+ # [('text/html', 1.0), ('text/plain', 0.5)]
90
+ #
91
+ # Type signature: ([(str, str, float)], [str]) -> [(str, float)]
92
+ if accept_types.nil? or accept_types == []
93
+ # Accept all of them
94
+ default = 1
95
+ else
96
+ default = 0
97
+ end
98
+
99
+ match_main = {}
100
+ match_sub = {}
101
+ accept_types.each { |main, sub, q|
102
+ if main == '*'
103
+ default = [default, q].max
104
+ next
105
+ elsif sub == '*'
106
+ match_main[main] = [match_main.fetch(main, 0), q].max
107
+ else
108
+ match_sub[[main, sub]] = [match_sub.fetch([main, sub], 0), q].max
109
+ end
110
+ }
111
+
112
+ accepted_list = []
113
+ order_maintainer = 0
114
+ have_types.each { |mtype|
115
+ main, sub = mtype.split('/', 2)
116
+ if match_sub.member?([main, sub])
117
+ q = match_sub[[main, sub]]
118
+ else
119
+ q = match_main.fetch(main, default)
120
+ end
121
+
122
+ if q != 0
123
+ accepted_list << [1 - q, order_maintainer, q, mtype]
124
+ order_maintainer += 1
125
+ end
126
+ }
127
+
128
+ accepted_list.sort!
129
+ return accepted_list.collect { |_, _, q, mtype| [mtype, q] }
130
+ end
131
+
132
+ def self.get_acceptable(accept_header, have_types)
133
+ # Parse the accept header and return a list of available types
134
+ # in preferred order. If a type is unacceptable, it will not be
135
+ # in the resulting list.
136
+ #
137
+ # This is a convenience wrapper around matchTypes and
138
+ # parse_accept_header
139
+ #
140
+ # (str, [str]) -> [str]
141
+ accepted = self.parse_accept_header(accept_header)
142
+ preferred = self.match_types(accepted, have_types)
143
+ return preferred.collect { |mtype, _| mtype }
144
+ end
145
+
146
+ end
147
+
148
+ end
@@ -0,0 +1,21 @@
1
+
2
+ require 'openid/yadis/accept'
3
+
4
+ module OpenID
5
+
6
+ module Yadis
7
+
8
+ YADIS_HEADER_NAME = 'X-XRDS-Location'
9
+ YADIS_CONTENT_TYPE = 'application/xrds+xml'
10
+
11
+ # A value suitable for using as an accept header when performing
12
+ # YADIS discovery, unless the application has special requirements
13
+ YADIS_ACCEPT_HEADER = generate_accept_header(
14
+ ['text/html', 0.3],
15
+ ['application/xhtml+xml', 0.5],
16
+ [YADIS_CONTENT_TYPE, 1.0]
17
+ )
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,153 @@
1
+
2
+ require 'openid/util'
3
+ require 'openid/fetchers'
4
+ require 'openid/yadis/constants'
5
+ require 'openid/yadis/parsehtml'
6
+
7
+ module OpenID
8
+
9
+ # Raised when a error occurs in the discovery process
10
+ class DiscoveryFailure < OpenIDError
11
+ attr_accessor :identity_url, :http_response
12
+
13
+ def initialize(message, http_response)
14
+ super(message)
15
+ @identity_url = nil
16
+ @http_response = http_response
17
+ end
18
+ end
19
+
20
+ module Yadis
21
+
22
+ # Contains the result of performing Yadis discovery on a URI
23
+ class DiscoveryResult
24
+
25
+ # The result of following redirects from the request_uri
26
+ attr_accessor :normalize_uri
27
+
28
+ # The URI from which the response text was returned (set to
29
+ # nil if there was no XRDS document found)
30
+ attr_accessor :xrds_uri
31
+
32
+ # The content-type returned with the response_text
33
+ attr_accessor :content_type
34
+
35
+ # The document returned from the xrds_uri
36
+ attr_accessor :response_text
37
+
38
+ attr_accessor :request_uri, :normalized_uri
39
+
40
+ def initialize(request_uri)
41
+ # Initialize the state of the object
42
+ #
43
+ # sets all attributes to None except the request_uri
44
+ @request_uri = request_uri
45
+ @normalized_uri = nil
46
+ @xrds_uri = nil
47
+ @content_type = nil
48
+ @response_text = nil
49
+ end
50
+
51
+ # Was the Yadis protocol's indirection used?
52
+ def used_yadis_location?
53
+ return @normalized_uri != @xrds_uri
54
+ end
55
+
56
+ # Is the response text supposed to be an XRDS document?
57
+ def is_xrds
58
+ return (used_yadis_location?() or
59
+ @content_type == YADIS_CONTENT_TYPE)
60
+ end
61
+ end
62
+
63
+ # Discover services for a given URI.
64
+ #
65
+ # uri: The identity URI as a well-formed http or https URI. The
66
+ # well-formedness and the protocol are not checked, but the
67
+ # results of this function are undefined if those properties do
68
+ # not hold.
69
+ #
70
+ # returns a DiscoveryResult object
71
+ #
72
+ # Raises DiscoveryFailure when the HTTP response does not have
73
+ # a 200 code.
74
+ def self.discover(uri)
75
+ result = DiscoveryResult.new(uri)
76
+ begin
77
+ resp = OpenID.fetch(uri, nil, {'Accept' => YADIS_ACCEPT_HEADER})
78
+ rescue Exception
79
+ raise DiscoveryFailure.new("Failed to fetch identity URL #{uri} : #{$!}", $!)
80
+ end
81
+ if resp.code != "200" and resp.code != "206"
82
+ raise DiscoveryFailure.new(
83
+ "HTTP Response status from identity URL host is not \"200\"."\
84
+ "Got status #{resp.code.inspect} for #{resp.final_url}", resp)
85
+ end
86
+
87
+ # Note the URL after following redirects
88
+ result.normalized_uri = resp.final_url
89
+
90
+ # Attempt to find out where to go to discover the document or if
91
+ # we already have it
92
+ result.content_type = resp['content-type']
93
+
94
+ result.xrds_uri = self.where_is_yadis?(resp)
95
+
96
+ if result.xrds_uri and result.used_yadis_location?
97
+ begin
98
+ resp = OpenID.fetch(result.xrds_uri)
99
+ rescue
100
+ raise DiscoveryFailure.new("Failed to fetch Yadis URL #{result.xrds_uri} : #{$!}", $!)
101
+ end
102
+ if resp.code != "200" and resp.code != "206"
103
+ exc = DiscoveryFailure.new(
104
+ "HTTP Response status from Yadis host is not \"200\". " +
105
+ "Got status #{resp.code.inspect} for #{resp.final_url}", resp)
106
+ exc.identity_url = result.normalized_uri
107
+ raise exc
108
+ end
109
+
110
+ result.content_type = resp['content-type']
111
+ end
112
+
113
+ result.response_text = resp.body
114
+ return result
115
+ end
116
+
117
+ # Given a HTTPResponse, return the location of the Yadis
118
+ # document.
119
+ #
120
+ # May be the URL just retrieved, another URL, or None, if I
121
+ # can't find any.
122
+ #
123
+ # [non-blocking]
124
+ def self.where_is_yadis?(resp)
125
+ # Attempt to find out where to go to discover the document or if
126
+ # we already have it
127
+ content_type = resp['content-type']
128
+
129
+ # According to the spec, the content-type header must be an
130
+ # exact match, or else we have to look for an indirection.
131
+ if (!content_type.nil? and !content_type.to_s.empty? and
132
+ content_type.split(';', 2)[0].downcase == YADIS_CONTENT_TYPE)
133
+ return resp.final_url
134
+ else
135
+ # Try the header
136
+ yadis_loc = resp[YADIS_HEADER_NAME.downcase]
137
+
138
+ if yadis_loc.nil?
139
+ # Parse as HTML if the header is missing.
140
+ #
141
+ # XXX: do we want to do something with content-type, like
142
+ # have a whitelist or a blacklist (for detecting that it's
143
+ # HTML)?
144
+ yadis_loc = Yadis.html_yadis_location(resp.body)
145
+ end
146
+ end
147
+
148
+ return yadis_loc
149
+ end
150
+
151
+ end
152
+
153
+ end