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,553 @@
1
+ require 'openid/util'
2
+ require 'openid/kvform'
3
+
4
+ module OpenID
5
+
6
+ IDENTIFIER_SELECT = 'http://specs.openid.net/auth/2.0/identifier_select'
7
+
8
+ # URI for Simple Registration extension, the only commonly deployed
9
+ # OpenID 1.x extension, and so a special case.
10
+ SREG_URI = 'http://openid.net/sreg/1.0'
11
+
12
+ # The OpenID 1.x namespace URIs
13
+ OPENID1_NS = 'http://openid.net/signon/1.0'
14
+ OPENID11_NS = 'http://openid.net/signon/1.1'
15
+ OPENID1_NAMESPACES = [OPENID1_NS, OPENID11_NS]
16
+
17
+ # The OpenID 2.0 namespace URI
18
+ OPENID2_NS = 'http://specs.openid.net/auth/2.0'
19
+
20
+ # The namespace consisting of pairs with keys that are prefixed with
21
+ # "openid." but not in another namespace.
22
+ NULL_NAMESPACE = :null_namespace
23
+
24
+ # The null namespace, when it is an allowed OpenID namespace
25
+ OPENID_NS = :openid_namespace
26
+
27
+ # The top-level namespace, excluding all pairs with keys that start
28
+ # with "openid."
29
+ BARE_NS = :bare_namespace
30
+
31
+ # Limit, in bytes, of identity provider and return_to URLs,
32
+ # including response payload. See OpenID 1.1 specification,
33
+ # Appendix D.
34
+ OPENID1_URL_LIMIT = 2047
35
+
36
+ # All OpenID protocol fields. Used to check namespace aliases.
37
+ OPENID_PROTOCOL_FIELDS = [
38
+ 'ns', 'mode', 'error', 'return_to',
39
+ 'contact', 'reference', 'signed',
40
+ 'assoc_type', 'session_type',
41
+ 'dh_modulus', 'dh_gen',
42
+ 'dh_consumer_public', 'claimed_id',
43
+ 'identity', 'realm', 'invalidate_handle',
44
+ 'op_endpoint', 'response_nonce', 'sig',
45
+ 'assoc_handle', 'trust_root', 'openid',
46
+ ]
47
+
48
+ # Sentinel used for Message implementation to indicate that getArg
49
+ # should raise an exception instead of returning a default.
50
+ NO_DEFAULT = :no_default
51
+
52
+ # Raised if the generic OpenID namespace is accessed when there
53
+ # is no OpenID namespace set for this message.
54
+ class UndefinedOpenIDNamespace < Exception; end
55
+
56
+ # Raised when an alias or namespace URI has already been registered.
57
+ class NamespaceAliasRegistrationError < Exception; end
58
+
59
+ # Raised if openid.ns is not a recognized value.
60
+ # See Message class variable @@allowed_openid_namespaces
61
+ class InvalidOpenIDNamespace < Exception; end
62
+
63
+ class Message
64
+ attr_reader :namespaces
65
+
66
+ # Raised when key lookup fails
67
+ class KeyNotFound < IndexError ; end
68
+
69
+ # Namespace / alias registration map. See
70
+ # register_namespace_alias.
71
+ @@registered_aliases = {}
72
+
73
+ # Registers a (namespace URI, alias) mapping in a global namespace
74
+ # alias map. Raises NamespaceAliasRegistrationError if either the
75
+ # namespace URI or alias has already been registered with a
76
+ # different value. This function is required if you want to use a
77
+ # namespace with an OpenID 1 message.
78
+ def Message.register_namespace_alias(namespace_uri, alias_)
79
+ if @@registered_aliases[alias_] == namespace_uri
80
+ return
81
+ end
82
+
83
+ if @@registered_aliases.values.include?(namespace_uri)
84
+ raise NamespaceAliasRegistrationError,
85
+ 'Namespace uri #{namespace_uri} already registered'
86
+ end
87
+
88
+ if @@registered_aliases.member?(alias_)
89
+ raise NamespaceAliasRegistrationError,
90
+ 'Alias #{alias_} already registered'
91
+ end
92
+
93
+ @@registered_aliases[alias_] = namespace_uri
94
+ end
95
+
96
+ @@allowed_openid_namespaces = [OPENID1_NS, OPENID2_NS, OPENID11_NS]
97
+
98
+ # Raises InvalidNamespaceError if you try to instantiate a Message
99
+ # with a namespace not in the above allowed list
100
+ def initialize(openid_namespace=nil)
101
+ @args = {}
102
+ @namespaces = NamespaceMap.new
103
+ if openid_namespace
104
+ implicit = OPENID1_NAMESPACES.member? openid_namespace
105
+ self.set_openid_namespace(openid_namespace, implicit)
106
+ else
107
+ @openid_ns_uri = nil
108
+ end
109
+ end
110
+
111
+ # Construct a Message containing a set of POST arguments.
112
+ # Raises InvalidNamespaceError if you try to instantiate a Message
113
+ # with a namespace not in the above allowed list
114
+ def Message.from_post_args(args)
115
+ m = Message.new
116
+ openid_args = {}
117
+ args.each do |key,value|
118
+ if value.is_a?(Array)
119
+ raise ArgumentError, "Query dict must have one value for each key, " +
120
+ "not lists of values. Query is #{args.inspect}"
121
+ end
122
+
123
+ prefix, rest = key.split('.', 2)
124
+
125
+ if prefix != 'openid' or rest.nil?
126
+ m.set_arg(BARE_NS, key, value)
127
+ else
128
+ openid_args[rest] = value
129
+ end
130
+ end
131
+
132
+ m._from_openid_args(openid_args)
133
+ return m
134
+ end
135
+
136
+ # Construct a Message from a parsed KVForm message.
137
+ # Raises InvalidNamespaceError if you try to instantiate a Message
138
+ # with a namespace not in the above allowed list
139
+ def Message.from_openid_args(openid_args)
140
+ m = Message.new
141
+ m._from_openid_args(openid_args)
142
+ return m
143
+ end
144
+
145
+ # Raises InvalidNamespaceError if you try to instantiate a Message
146
+ # with a namespace not in the above allowed list
147
+ def _from_openid_args(openid_args)
148
+ ns_args = []
149
+
150
+ # resolve namespaces
151
+ openid_args.each { |rest, value|
152
+ ns_alias, ns_key = rest.split('.', 2)
153
+ if ns_key.nil?
154
+ ns_alias = NULL_NAMESPACE
155
+ ns_key = rest
156
+ end
157
+
158
+ if ns_alias == 'ns'
159
+ @namespaces.add_alias(value, ns_key)
160
+ elsif ns_alias == NULL_NAMESPACE and ns_key == 'ns'
161
+ set_openid_namespace(value, false)
162
+ else
163
+ ns_args << [ns_alias, ns_key, value]
164
+ end
165
+ }
166
+
167
+ # implicitly set an OpenID 1 namespace
168
+ unless get_openid_namespace
169
+ set_openid_namespace(OPENID1_NS, true)
170
+ end
171
+
172
+ # put the pairs into the appropriate namespaces
173
+ ns_args.each { |ns_alias, ns_key, value|
174
+ ns_uri = @namespaces.get_namespace_uri(ns_alias)
175
+ unless ns_uri
176
+ ns_uri = _get_default_namespace(ns_alias)
177
+ unless ns_uri
178
+ ns_uri = get_openid_namespace
179
+ ns_key = "#{ns_alias}.#{ns_key}"
180
+ else
181
+ @namespaces.add_alias(ns_uri, ns_alias, true)
182
+ end
183
+ end
184
+ self.set_arg(ns_uri, ns_key, value)
185
+ }
186
+ end
187
+
188
+ def _get_default_namespace(mystery_alias)
189
+ # only try to map an alias to a default if it's an
190
+ # OpenID 1.x namespace
191
+ if is_openid1
192
+ @@registered_aliases[mystery_alias]
193
+ end
194
+ end
195
+
196
+ def set_openid_namespace(openid_ns_uri, implicit)
197
+ if !@@allowed_openid_namespaces.include?(openid_ns_uri)
198
+ raise InvalidOpenIDNamespace, "Invalid null namespace: #{openid_ns_uri}"
199
+ end
200
+ @namespaces.add_alias(openid_ns_uri, NULL_NAMESPACE, implicit)
201
+ @openid_ns_uri = openid_ns_uri
202
+ end
203
+
204
+ def get_openid_namespace
205
+ return @openid_ns_uri
206
+ end
207
+
208
+ def is_openid1
209
+ return OPENID1_NAMESPACES.member?(@openid_ns_uri)
210
+ end
211
+
212
+ def is_openid2
213
+ return @openid_ns_uri == OPENID2_NS
214
+ end
215
+
216
+ # Create a message from a KVForm string
217
+ def Message.from_kvform(kvform_string)
218
+ return Message.from_openid_args(Util.kv_to_dict(kvform_string))
219
+ end
220
+
221
+ def copy
222
+ return Marshal.load(Marshal.dump(self))
223
+ end
224
+
225
+ # Return all arguments with "openid." in from of namespaced arguments.
226
+ def to_post_args
227
+ args = {}
228
+
229
+ # add namespace defs to the output
230
+ @namespaces.each { |ns_uri, ns_alias|
231
+ if @namespaces.implicit?(ns_uri)
232
+ next
233
+ end
234
+ if ns_alias == NULL_NAMESPACE
235
+ ns_key = 'openid.ns'
236
+ else
237
+ ns_key = 'openid.ns.' + ns_alias
238
+ end
239
+ args[ns_key] = ns_uri
240
+ }
241
+
242
+ @args.each { |k, value|
243
+ ns_uri, ns_key = k
244
+ key = get_key(ns_uri, ns_key)
245
+ args[key] = value
246
+ }
247
+
248
+ return args
249
+ end
250
+
251
+ # Return all namespaced arguments, failing if any non-namespaced arguments
252
+ # exist.
253
+ def to_args
254
+ post_args = self.to_post_args
255
+ kvargs = {}
256
+ post_args.each { |k,v|
257
+ if !k.starts_with?('openid.')
258
+ raise ArgumentError, "This message can only be encoded as a POST, because it contains arguments that are not prefixed with 'openid.'"
259
+ else
260
+ kvargs[k[7..-1]] = v
261
+ end
262
+ }
263
+ return kvargs
264
+ end
265
+
266
+ # Generate HTML form markup that contains the values in this
267
+ # message, to be HTTP POSTed as x-www-form-urlencoded UTF-8.
268
+ def to_form_markup(action_url, form_tag_attrs=nil, submit_text='Continue')
269
+ form_tag_attr_map = {}
270
+
271
+ if form_tag_attrs
272
+ form_tag_attrs.each { |name, attr|
273
+ form_tag_attr_map[name] = attr
274
+ }
275
+ end
276
+
277
+ form_tag_attr_map['action'] = action_url
278
+ form_tag_attr_map['method'] = 'post'
279
+ form_tag_attr_map['accept-charset'] = 'UTF-8'
280
+ form_tag_attr_map['enctype'] = 'application/x-www-form-urlencoded'
281
+
282
+ markup = "<form "
283
+
284
+ form_tag_attr_map.each { |k, v|
285
+ markup += " #{k}=\"#{v}\""
286
+ }
287
+
288
+ markup += ">\n"
289
+
290
+ to_post_args.each { |k,v|
291
+ markup += "<input type='hidden' name='#{k}' value='#{OpenID::Util.html_encode(v)}' />\n"
292
+ }
293
+ markup += "<input type='submit' value='#{submit_text}' />\n"
294
+ markup += "\n</form>"
295
+ return markup
296
+ end
297
+
298
+ # Generate a GET URL with the paramters in this message attacked as
299
+ # query parameters.
300
+ def to_url(base_url)
301
+ return Util.append_args(base_url, self.to_post_args)
302
+ end
303
+
304
+ # Generate a KVForm string that contains the parameters in this message.
305
+ # This will fail is the message contains arguments outside of the
306
+ # "openid." prefix.
307
+ def to_kvform
308
+ return Util.dict_to_kv(to_args)
309
+ end
310
+
311
+ # Generate an x-www-urlencoded string.
312
+ def to_url_encoded
313
+ args = to_post_args.map.sort
314
+ return Util.urlencode(args)
315
+ end
316
+
317
+ # Convert an input value into the internally used values of this obejct.
318
+ def _fix_ns(namespace)
319
+ if namespace == OPENID_NS
320
+ unless @openid_ns_uri
321
+ raise UndefinedOpenIDNamespace, 'OpenID namespace not set'
322
+ else
323
+ namespace = @openid_ns_uri
324
+ end
325
+ end
326
+
327
+ if namespace == BARE_NS
328
+ return namespace
329
+ end
330
+
331
+ if !namespace.is_a?(String)
332
+ raise ArgumentError, ("Namespace must be BARE_NS, OPENID_NS or "\
333
+ "a string. Got #{namespace.inspect}")
334
+ end
335
+
336
+ if namespace.index(':').nil?
337
+ msg = ("OpenID 2.0 namespace identifiers SHOULD be URIs. "\
338
+ "Got #{namespace.inspect}")
339
+ Util.log(msg)
340
+
341
+ if namespace == 'sreg'
342
+ msg = "Using #{SREG_URI} instead of \"sreg\" as namespace"
343
+ Util.log(msg)
344
+ return SREG_URI
345
+ end
346
+ end
347
+
348
+ return namespace
349
+ end
350
+
351
+ def has_key?(namespace, ns_key)
352
+ namespace = _fix_ns(namespace)
353
+ return @args.member?([namespace, ns_key])
354
+ end
355
+
356
+ # Get the key for a particular namespaced argument
357
+ def get_key(namespace, ns_key)
358
+ namespace = _fix_ns(namespace)
359
+ return ns_key if namespace == BARE_NS
360
+
361
+ ns_alias = @namespaces.get_alias(namespace)
362
+
363
+ # no alias is defined, so no key can exist
364
+ return nil if ns_alias.nil?
365
+
366
+ if ns_alias == NULL_NAMESPACE
367
+ tail = ns_key
368
+ else
369
+ tail = "#{ns_alias}.#{ns_key}"
370
+ end
371
+
372
+ return 'openid.' + tail
373
+ end
374
+
375
+ # Get a value for a namespaced key.
376
+ def get_arg(namespace, key, default=nil)
377
+ namespace = _fix_ns(namespace)
378
+ @args.fetch([namespace, key]) {
379
+ if default == NO_DEFAULT
380
+ raise KeyNotFound, "<#{namespace}>#{key} not in this message"
381
+ else
382
+ default
383
+ end
384
+ }
385
+ end
386
+
387
+ # Get the arguments that are defined for this namespace URI.
388
+ def get_args(namespace)
389
+ namespace = _fix_ns(namespace)
390
+ args = {}
391
+ @args.each { |k,v|
392
+ pair_ns, ns_key = k
393
+ args[ns_key] = v if pair_ns == namespace
394
+ }
395
+ return args
396
+ end
397
+
398
+ # Set multiple key/value pairs in one call.
399
+ def update_args(namespace, updates)
400
+ namespace = _fix_ns(namespace)
401
+ updates.each {|k,v| set_arg(namespace, k, v)}
402
+ end
403
+
404
+ # Set a single argument in this namespace
405
+ def set_arg(namespace, key, value)
406
+ namespace = _fix_ns(namespace)
407
+ @args[[namespace, key].freeze] = value
408
+ if namespace != BARE_NS
409
+ @namespaces.add(namespace)
410
+ end
411
+ end
412
+
413
+ # Remove a single argument from this namespace.
414
+ def del_arg(namespace, key)
415
+ namespace = _fix_ns(namespace)
416
+ _key = [namespace, key]
417
+ @args.delete(_key)
418
+ end
419
+
420
+ def ==(other)
421
+ other.is_a?(self.class) && @args == other.instance_eval { @args }
422
+ end
423
+
424
+ def get_aliased_arg(aliased_key, default=nil)
425
+ if aliased_key == 'ns'
426
+ return get_openid_namespace()
427
+ end
428
+
429
+ ns_alias, key = aliased_key.split('.', 2)
430
+ if ns_alias == 'ns'
431
+ uri = @namespaces.get_namespace_uri(key)
432
+ if uri.nil? and default == NO_DEFAULT
433
+ raise KeyNotFound, "Namespace #{key} not defined when looking "\
434
+ "for #{aliased_key}"
435
+ else
436
+ return (uri.nil? ? default : uri)
437
+ end
438
+ end
439
+
440
+ if key.nil?
441
+ key = aliased_key
442
+ ns = nil
443
+ else
444
+ ns = @namespaces.get_namespace_uri(ns_alias)
445
+ end
446
+
447
+ if ns.nil?
448
+ key = aliased_key
449
+ ns = get_openid_namespace
450
+ end
451
+
452
+ return get_arg(ns, key, default)
453
+ end
454
+ end
455
+
456
+
457
+ # Maintains a bidirectional map between namespace URIs and aliases.
458
+ class NamespaceMap
459
+
460
+ def initialize
461
+ @alias_to_namespace = {}
462
+ @namespace_to_alias = {}
463
+ @implicit_namespaces = []
464
+ end
465
+
466
+ def get_alias(namespace_uri)
467
+ @namespace_to_alias[namespace_uri]
468
+ end
469
+
470
+ def get_namespace_uri(namespace_alias)
471
+ @alias_to_namespace[namespace_alias]
472
+ end
473
+
474
+ # Add an alias from this namespace URI to the alias.
475
+ def add_alias(namespace_uri, desired_alias, implicit=false)
476
+ # Check that desired_alias is not an openid protocol field as
477
+ # per the spec.
478
+ Util.assert(!OPENID_PROTOCOL_FIELDS.include?(desired_alias),
479
+ "#{desired_alias} is not an allowed namespace alias")
480
+
481
+ # check that there is not a namespace already defined for the
482
+ # desired alias
483
+ current_namespace_uri = @alias_to_namespace.fetch(desired_alias, nil)
484
+ if current_namespace_uri and current_namespace_uri != namespace_uri
485
+ raise IndexError, "Cannot map #{namespace_uri} to alias #{desired_alias}. #{current_namespace_uri} is already mapped to alias #{desired_alias}"
486
+ end
487
+
488
+ # Check that desired_alias does not contain a period as per the
489
+ # spec.
490
+ if desired_alias.is_a?(String)
491
+ Util.assert(desired_alias.index('.').nil?,
492
+ "#{desired_alias} must not contain a dot")
493
+ end
494
+
495
+ # check that there is not already a (different) alias for this
496
+ # namespace URI.
497
+ _alias = @namespace_to_alias[namespace_uri]
498
+ if _alias and _alias != desired_alias
499
+ raise IndexError, "Cannot map #{namespace_uri} to alias #{desired_alias}. It is already mapped to alias #{_alias}"
500
+ end
501
+
502
+ @alias_to_namespace[desired_alias] = namespace_uri
503
+ @namespace_to_alias[namespace_uri] = desired_alias
504
+ @implicit_namespaces << namespace_uri if implicit
505
+ return desired_alias
506
+ end
507
+
508
+ # Add this namespace URI to the mapping, without caring what alias
509
+ # it ends up with.
510
+ def add(namespace_uri)
511
+ # see if this namepace is already mapped to an alias
512
+ _alias = @namespace_to_alias[namespace_uri]
513
+ return _alias if _alias
514
+
515
+ # Fall back to generating a numberical alias
516
+ i = 0
517
+ while true
518
+ _alias = 'ext' + i.to_s
519
+ begin
520
+ add_alias(namespace_uri, _alias)
521
+ rescue IndexError
522
+ i += 1
523
+ else
524
+ return _alias
525
+ end
526
+ end
527
+
528
+ raise StandardError, 'Unreachable'
529
+ end
530
+
531
+ def member?(namespace_uri)
532
+ @namespace_to_alias.has_key?(namespace_uri)
533
+ end
534
+
535
+ def each
536
+ @namespace_to_alias.each {|k,v| yield k,v}
537
+ end
538
+
539
+ def namespace_uris
540
+ # Return an iterator over the namespace URIs
541
+ return @namespace_to_alias.keys()
542
+ end
543
+
544
+ def implicit?(namespace_uri)
545
+ return @implicit_namespaces.member?(namespace_uri)
546
+ end
547
+
548
+ def aliases
549
+ # Return an iterator over the aliases
550
+ return @alias_to_namespace.keys()
551
+ end
552
+ end
553
+ end