XMLCanonicalizer 0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -1,61 +1,304 @@
1
- == C14N-r
1
+ == WSS4R
2
2
 
3
- Project home: www.rubyforge.org/projects/c14n-r
3
+ Project home: www.rubyforge.org/projects/wss4r
4
4
  Author : Roland Schmitt, roland.schmitt@web.de
5
- Date : 12.05.2007
5
+ Date : 01.02.2006
6
6
 
7
- Version : 0.1
7
+ Version : 0.3
8
8
 
9
9
  = Contents
10
10
  1. What is it (and what is it not)
11
11
  2. Requirements
12
12
  3. Installation
13
13
  4. Usage
14
+ 4.1. Resolver
15
+ 4.2. UsernameToken
16
+ 4.3. Encryption
17
+ 4.4. Signature
18
+ 4.5. Signature/Encryption
19
+ 4.6. Interoperability with WSE 2.0
20
+ 4.7. Interoperability with JWSDP 2.0
21
+ 4.8. Integration into rails
14
22
  5. Samples
23
+ 5.1. A simple example
24
+ 5.2. Rails example
15
25
  6. License
16
26
  7. Support
17
27
  8. URLs
18
28
 
29
+
30
+
19
31
  = 1. What is it (and what is it not)
20
- C14N-r stands for "xml canonicalizer for ruby". It implements the "Canonical XML
21
- Version 1.0" recommendation from the w3c [1].
22
- c14n-r is a sub-project from wss4r [2], an implementation of some web service security standards.
32
+ WSS4R (Web Service Security For Ruby) is a library that implements some of the
33
+ standards for web service security defined by the oasis open consortium [1].
34
+ It is a proof of concept (or "Can i do it with ruby?") and not an fully featured
35
+ implementation, so it's focussed on the encryption and signature aspects of
36
+ web services. WSS4R sits on top of the famous soap4r library of NAKAMURA Hiroshi [2],
37
+ so implementing servers or clients that uses data encryption or signatures is easy
38
+ when you know how to use soap4r.
39
+ Besides that there is a integration into the rails [3] application server, so you
40
+ can use the features of WSS4R in rails driven web services.
23
41
 
24
- If you like it or hate it or want more features, drop me an email at Roland.Schmitt@web.de.
42
+ I've tested WSS4R with the following counterparts:
43
+ - Web Service Enhancements 2.0 [8]
44
+ - Java Web Service Development Pack 2.0 [9]
45
+
25
46
 
47
+ WSS4R is my first ruby project, so it is not very ruby like in most places nor is it
48
+ a example of good ruby programming in general. It was started mostly to learn ruby,
49
+ not to implement an full featured WS-Security conform library.
50
+
51
+ If you like it or hate it or want more features, drop me an email at Roland.Schmitt@web.de.
52
+
53
+
26
54
  = 2. Requirements
27
- log4r >= 1.0.4
55
+ - Ruby [4] with compiled bindings to openssl [6]
56
+ (tested only with Ruby 1.8.4)
57
+ - soap4r [2]
58
+ (tested with soap4r version from 04. Dez. 2005),
59
+ - Log4r [5]
60
+ (tested with version 1.0.5)
61
+
62
+ Optional (for the examples):
63
+ - Rails [3]
64
+ (tested with version 1.0.0)
65
+ - Sqlite3-Ruby [7]
66
+ (tested with version 1.1.0)
67
+
68
+
28
69
 
29
70
  = 3. Installation
30
- Simly do:
31
- gem install --local XMLCanonicalizer-0.1.gem
71
+ Simly do
32
72
 
73
+ ruby setup.rb
74
+
75
+
33
76
  = 4. Usage
34
- require "xmlcanonicalizer"
35
- c = Xml::Util::XmlCanonicalizer.new(true,true) #XmlCanonicalizer.new(WITH_COMMENTS, EXCLUSIVE_MODE)
36
- c.canonicalize_element(element, false) #XmlCanonicalizer::canonicalize_element(element, LOGGING)
77
+ To use WSS4R, one have to require the new driver class
78
+
79
+ require "wss4r/rpc/driver"
80
+
81
+ instead of
82
+ require "soap/rpc/driver"
83
+
84
+
85
+ = 4.1. Resolver
86
+ Resolver objects are used to find certificates, keys and to authenticate users.
87
+ Resolver objects know how to get the corresponding private key for a certificate or how to load
88
+ a certificate identified by a name.
89
+ For example, when a client sends a encrypted request to the server, there is only the certificate
90
+ embedded in the message. A resolver object is responsible for loading the private key of the
91
+ certificate.
92
+
93
+ There two implementations of resolvers:
94
+ - CertificateDirectoryResolver
95
+ Loads keys/certificates from files in a specified directory in the file system.
96
+
97
+ - DatabaseResolver
98
+ Loads keys/certificates from sqlite3 databases.
99
+
100
+
101
+ = 4.2. UsernameToken
102
+ Example:
103
+
104
+ ...
105
+ driver = Driver.new('http://localhost:8070/','urn:multiply')
106
+ driver.add_method('multiply','a','b')
107
+ ...
108
+ usernametoken = UsernameToken.new("username", "password")
109
+ driver.security().add_security_token(usernametoken)
110
+ ...
111
+
112
+ The client is authenticated with his username and password. The password is not sended as clear
113
+ text, instead a hash function is used.
114
+
115
+
116
+ = 4.3. Encryption
117
+ Example:
118
+
119
+ ...
120
+ resolver = CertificateDirectoryResolver.new("../certs/ca")
121
+ certificate = resolver.certificate_by_subject("/C=DE/ST=Rheinland-Pfalz/L=Trier/O=FF/OU=Development/CN=Server/emailAddress=server@web.de")
122
+ x509 = X509SecurityToken.new(certificate)
123
+ enc_data = EncryptedData.new(x509)
124
+ driver.security().add_security_token(enc_data)
125
+ ...
126
+
127
+ The soap body is encrypted with the TripleDES algorithm. The used encryption key is then
128
+ encrypted with the certificates public key and placed in the soap header.
129
+
130
+ Actually only TripleDES and AES are supported by WSS4R as encryption algorithms. To use AES instead of the default
131
+ TripleDES, set:
132
+ enc_data.sessionkey_algorithm=(Types::ALGORITHM_AES_CBC)
133
+
134
+
135
+ = 4.4. Signature
136
+ Example:
137
+
138
+ ...
139
+ sign_cert = OpenSSL::X509::Certificate.new(File.read("../certs/wse/wse-client.cer"))
140
+ pkey = OpenSSL::PKey::RSA.new(File.read("../certs/wse/wse-client.key"))
141
+ x509 = X509SecurityToken.new(sign_cert, pkey)
142
+ signature = Signature.new(x509)
143
+ driver.security().add_security_token(signature)
144
+ ...
145
+
146
+ The soap body and the soap header timestamp elements are signed with the supplied certificate. The signature
147
+ is embedded in the soap header.
148
+
149
+
150
+ = 4.5. Signature/Encryption
151
+ Example:
152
+
153
+ ...
154
+ resolver = CertificateDirectoryResolver.new("../certs/wse")
155
+ driver.security().add_security_resolver(resolver)
156
+ sign_cert = OpenSSL::X509::Certificate.new(File.read("../certs/wse/wse-client.cer"))
157
+ pkey = OpenSSL::PKey::RSA.new(File.read("../certs/wse/wse-client.key"))
158
+ x509 = X509SecurityToken.new(sign_cert, pkey)
159
+ signature = Signature.new(x509)
160
+ driver.security().add_security_token(signature)
161
+ encrypt_cert = OpenSSL::X509::Certificate.new(File.read("../certs/wse/wse-server.cer"))
162
+ x509 = X509SecurityToken.new(encrypt_cert)
163
+ enc_data = EncryptedData.new(x509)
164
+ enc_data.sessionkey_algorithm=(Types::ALGORITHM_AES_CBC)
165
+ driver.security().add_security_token(enc_data)
166
+ ...
167
+
168
+ You can combine signature and encryption. In most cases, for encryption the clients certificate is used and
169
+ for signature the certificate of the server.
170
+ If you first apply the encryption, the signature is generated over the encrypted data. When signing is the first step, the
171
+ the signature is generated from the plain content. So it is important to know which token is first added to the driver object.
172
+
173
+
174
+ = 4.6. Interoperability with WSE 2.0
175
+ Should work with usernames, encryption and signatures.
176
+ Sample Visual Studio projects are provided in examples/WebServiceTest (client) and examples/WebService (server).
177
+
178
+
179
+ = 4.7. Interoperability with JWSDP 2.0
180
+ Should work with usernames, encryption and signatures.
181
+ Per default the examples the JWSDP works with keyIdendifiers for finding certificates and keys.
182
+ WSS4R does not support the keyIdentifier mechanism to identify certificates, because it is not a standard.
183
+
184
+
185
+ = 4.8. Integration into rails
186
+ To use WSS4R in rails one have to modify the controller that implements the web service:
187
+
188
+ require "wss4r/aws/utils"
189
+ require "activerecordresolver"
190
+
191
+ class SimpleServiceController < ApplicationController
192
+ wsdl_service_name 'SimpleService'
193
+ web_service_scaffold :invoke
194
+ web_service_api SimpleServiceApi
195
+
196
+ wss_add_resolvers([ActiveRecordResolver.new()])
197
+
198
+
199
+ I've only tested the direct dispatching mode of action web service with WSS4R.
200
+
37
201
 
38
202
  = 5. Examples
39
- require "xmlcanonicalizer"
40
- require "rexml/document"
41
- include REXML
42
- string = <<EOF
43
- <mydoc>
44
- <someelement attribute="nanoo">Text, text, text</someelement><anotherelement/>
45
- </mydoc>
46
- EOF
47
- doc = Document.new(string)
48
- c = XML::Util::XmlCanonicalizer.new(true,true)
49
- doc = c.canonicalize(doc)
50
- puts(doc.to_s())
203
+ All examples are placed in the examples subfolder.
204
+
205
+ certs Folder with various certificates and keys for the different examples
206
+ |-- ca Generated certificates and keys for the WSS4R examples
207
+ |-- jwsdp_15 Certificates and keys for to use with the JWSDP 1.5
208
+ |-- jwsdp_16 Certificates and keys for to use with the JWSDP 1.6/2.0
209
+ |-- wse Certificates and keys for to use with the WSE 2.0
210
+
211
+ clients
212
+ PlainNET.rb Example for using a .NET web service without web service security features.
213
+ PlainXWS.rb Example for using a JWSDP web service without web service security features.
214
+ TestNET.rb Example for using a WSE 2.0 web service. Shows usenametoken, encryption and signature.
215
+ Client for the project in the WebService folder.
216
+ TestXWS.rb Example for using a JWSDP 2.0 web service. Shows usenametoken, encryption and signature.
217
+ Client for the examples bundled with the JWSDP 2.0 package. The service is found in
218
+ %JWSDP_HOME%/xws-security/samples/simple. To work, set the the keyReferenceType in the
219
+ JWSDP xml config files under config/ to "Direct".
220
+ TestWSS4R.rb Example for using a WSS4R/soap4r web service. Shows usenametoken, encryption and signature.
221
+ Used with the server in the server folder.
222
+
223
+ rails
224
+ |-- simple Example for rails integration. Requires sqlite3-ruby.
225
+ |-- client Test client for the rails web service.
226
+ |-- app Files for the web service
227
+ |-- controllers Implementration of the web service and setup for the resolver, encryption and signing.
228
+ |-- helpers Resolver implementation that uses ActiveRecord to load certificates and keys.
229
+ |-- databases Sqlite3 database with certificates and keys.
230
+
231
+ server
232
+ |-- TestServer.rb WebRick server using soap4r and WSS4R.
233
+
234
+ WebService Visual Studio project for a WSE 2.0 enabled web service. Created with Visual Studio 2003 and
235
+ C#.
236
+
237
+ WebServiceTest Visual Studio project with clients for the WebService project and for the rails example. Created with
238
+ Visual Studio 2003 and C#.
239
+
240
+
241
+ = 5.1. A simple example
242
+ At the command line, go to examples/server and type:
243
+
244
+ ruby TestServer.rb user
245
+
246
+ A WebRick server starts that requires a username/password from the client, where the password is the username reversed.
247
+ In another shell, change the working dir to examples/clients and type:
248
+
249
+ ruby TestWSS4R.rb user
250
+
251
+ It show the result of the multiplication of the 2 arguments. The client uses "Ron" as username and "noR" as password. Setting
252
+ the password to other values than "noR" in the TestWSS4R.rb file results in a "User not authenticatd!" message.
253
+
254
+ Stop the TestServer with CTRL-Z (or CTRL-C). Restart it with
255
+
256
+ ruby TestServer.rb enc sign
257
+
258
+ The server now will first encrypt any request, then signing it.
51
259
 
260
+ Start the client by typing:
261
+
262
+ ruby TestClient.rb sign enc
263
+
264
+ The client first signs the request, then encrypts it and shows the response.
265
+
266
+ You can use various monitoring tools like the tcpmon utility from the axis project [10] to view the
267
+ resulting request/response messages.
268
+
269
+ = 5.2. Rails example
270
+ Go to examples/rails/simple and type
271
+
272
+ ruby script/server
273
+
274
+ To start the client, open a new shell and go to examples/rails/simple/client.
275
+
276
+ ruby client.rb
277
+
278
+ The output shows the reversed string that the client sents to the server. The client signs his request and the server encrypts
279
+ and signs the response.
280
+
281
+
52
282
  = 6. License
53
- C14N-r is licensed under GPL and Ruby's custom license. See GPL and RUBYS.
283
+
284
+ WSS4R is licensed under GPL and Ruby's custom license. See GPL and RUBYS.
285
+
54
286
 
55
287
  = 7. Support
56
- The RubyForge mailing list is at www.rubyforge.org/projects/c14n-r.
57
- Or, to contact the author, send mail to Roland.Schmitt@web.de
288
+
289
+ The RubyForge mailing list is at www.rubyforge.org/projects/wss4r.
290
+
291
+ Or, to contact the author, send mail to Roland.Schmitt@web.de
292
+
58
293
 
59
294
  = 8. URLs
60
- [1] - http://www.w3.org/TR/xml-c14n
61
- [2] - http://www.rubyforge.org/projects/wss4r
295
+ [1] - http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss
296
+ [2] - http://dev.ctor.org/soap4r/
297
+ [3] - http://www.rubyonrails.org
298
+ [4] - http://www.ruby-lang.org
299
+ [5] - http://log4r.sourceforge.net/
300
+ [6] - http://www.openssl.org
301
+ [7] - http://rubyforge.org/projects/sqlite-ruby/
302
+ [8] - http://msdn.microsoft.com/webservices/webservices/building/wse/default.aspx
303
+ [9] - https://jwsdp.dev.java.net/
304
+ [10] - http://ws.apache.org/axis/
@@ -256,7 +256,11 @@ module XML
256
256
 
257
257
  def write_attribute_axis(node)
258
258
  list = Array.new()
259
- node.attributes().each_attribute{|attr|
259
+ #Sorting-Bug
260
+ #node.attributes().each_attribute{|attr|
261
+ # list.push(attr) if (!is_namespace_node(attr.value()) && !is_namespace_decl(attr)) # && is_node_visible(
262
+ #}
263
+ node.attributes().sort().each{|key,attr|
260
264
  list.push(attr) if (!is_namespace_node(attr.value()) && !is_namespace_decl(attr)) # && is_node_visible(
261
265
  }
262
266
  if (!@exclusive && node.parent() != nil && node.parent().parent() != nil)
@@ -0,0 +1,438 @@
1
+ #require "rexml/document"
2
+ #require "base64"
3
+ #require "log4r"
4
+
5
+ #include REXML
6
+ #include Log4r
7
+
8
+ module XML
9
+ module Util
10
+
11
+ class REXML::Instruction
12
+ def write(writer, indent=-1, transitive=false, ie_hack=false)
13
+ indent(writer, indent)
14
+ writer << START.sub(/\\/u, '')
15
+ writer << @target
16
+ writer << ' '
17
+ writer << @content if @content != nil
18
+ writer << STOP.sub(/\\/u, '')
19
+ end
20
+ end
21
+
22
+ class REXML::Attribute
23
+ def <=>(a2)
24
+ if (self === a2)
25
+ return 0
26
+ elsif (self == nil)
27
+ return -1
28
+ elsif (a2 == nil)
29
+ return 1
30
+ elsif (self.prefix() == a2.prefix())
31
+ return self.name()<=>a2.name()
32
+ end
33
+ if (self.prefix() == nil)
34
+ return -1
35
+ elsif (a2.prefix() == nil)
36
+ return 1
37
+ end
38
+ ret = self.namespace()<=>a2.namespace()
39
+ if (ret == 0)
40
+ ret = self.prefix()<=>a2.prefix()
41
+ end
42
+ return ret
43
+ end
44
+ end
45
+
46
+ class REXML::Element
47
+ def search_namespace(prefix)
48
+ if (self.namespace(prefix) == nil)
49
+ return (self.parent().search_namespace(prefix)) if (self.parent() != nil)
50
+ else
51
+ return self.namespace(prefix)
52
+ end
53
+ end
54
+ def rendered=(rendered)
55
+ @rendered = rendered
56
+ end
57
+ def rendered?()
58
+ return @rendered
59
+ end
60
+ def node_namespaces()
61
+ ns = Array.new()
62
+ ns.push(self.prefix())
63
+ self.attributes().each_attribute{|a|
64
+ if (a.prefix() != nil)
65
+ ns.push(a.prefix())
66
+ end
67
+ if (a.prefix() == "" && a.local_name() == "xmlns")
68
+ ns.push("xmlns")
69
+ end
70
+ }
71
+ ns
72
+ end
73
+ end
74
+
75
+ class NamespaceNode
76
+ attr_reader :prefix, :uri
77
+ def initialize(prefix, uri)
78
+ @prefix = prefix
79
+ @uri = uri
80
+ end
81
+ end
82
+
83
+ class XmlCanonicalizer
84
+ attr_accessor :prefix_list, :logger
85
+
86
+ BEFORE_DOC_ELEMENT = 0
87
+ INSIDE_DOC_ELEMENT = 1
88
+ AFTER_DOC_ELEMENT = 2
89
+
90
+ NODE_TYPE_ATTRIBUTE = 3
91
+ NODE_TYPE_WHITESPACE = 4
92
+ NODE_TYPE_COMMENT = 5
93
+ NODE_TYPE_PI = 6
94
+ NODE_TYPE_TEXT = 7
95
+
96
+
97
+ def initialize(with_comments, excl_c14n)
98
+ @with_comments = with_comments
99
+ @exclusive = excl_c14n
100
+ @res = ""
101
+ @state = BEFORE_DOC_ELEMENT
102
+ @xnl = Array.new()
103
+ @prevVisibleNamespacesStart = 0
104
+ @prevVisibleNamespacesEnd = 0
105
+ @visibleNamespaces = Array.new()
106
+ @inclusive_namespaces = Array.new()
107
+ @prefix_list = nil
108
+ @rendered_prefixes = Array.new()
109
+ end
110
+
111
+ def add_inclusive_namespaces(prefix_list, element, visible_namespaces)
112
+ namespaces = element.attributes()
113
+ namespaces.each_attribute{|ns|
114
+ if (ns.prefix=="xmlns")
115
+ if (prefix_list.include?(ns.local_name()))
116
+ visible_namespaces.push(NamespaceNode.new("xmlns:"+ns.local_name(), ns.value()))
117
+ end
118
+ end
119
+ }
120
+ parent = element.parent()
121
+ add_inclusive_namespaces(prefix_list, parent, visible_namespaces) if (parent)
122
+ visible_namespaces
123
+ end
124
+
125
+ def canonicalize(document)
126
+ write_document_node(document)
127
+ @res
128
+ end
129
+
130
+ def canonicalize_element(element, logging = true)
131
+ logging=(true) if logging
132
+ @logger.debug("Canonicalize element:\n " + element.to_s()) if @logger
133
+ @inclusive_namespaces = add_inclusive_namespaces(@prefix_list, element, @inclusive_namespaces) if (@prefix_list)
134
+ @preserve_document = element.document()
135
+ tmp_parent = element.parent()
136
+ body_string = remove_whitespace(element.to_s().gsub("\n","").gsub("\t","").gsub("\r",""))
137
+ document = Document.new(body_string)
138
+ tmp_parent.delete_element(element)
139
+ element = tmp_parent.add_element(document.root())
140
+ @preserve_element = element
141
+ document = Document.new(element.to_s())
142
+ ns = element.namespace(element.prefix())
143
+ document.root().add_namespace(element.prefix(), ns)
144
+ write_document_node(document)
145
+ @logger.debug("Canonicalized result:\n " + @res.to_s()) if @logger
146
+ @res
147
+ end
148
+
149
+ def write_document_node(document)
150
+ @state = BEFORE_DOC_ELEMENT
151
+ if (document.class().to_s() == "REXML::Element")
152
+ write_node(document)
153
+ else
154
+ document.each_child{|child|
155
+ write_node(child)
156
+ }
157
+ end
158
+ @res
159
+ end
160
+
161
+ def write_node(node)
162
+ visible = is_node_visible(node)
163
+ if ((node.node_type() == :text) && white_text?(node.value()))
164
+ res = node.value()
165
+ res.gsub("\r\n","\n")
166
+ #res = res.delete(" ").delete("\t")
167
+ res.delete("\r")
168
+ @res = @res + res
169
+ #write_text_node(node,visible) if (@state == INSIDE_DOC_ELEMENT)
170
+ return
171
+ end
172
+ if (node.node_type() == :text)
173
+ write_text_node(node, visible)
174
+ return
175
+ end
176
+ if (node.node_type() == :element)
177
+ write_element_node(node, visible) if (!node.rendered?())
178
+ node.rendered=(true)
179
+ end
180
+ if (node.node_type() == :processing_instruction)
181
+ end
182
+ if (node.node_type() == :comment)
183
+ end
184
+ end
185
+
186
+ def write_element_node(node, visible)
187
+ savedPrevVisibleNamespacesStart = @prevVisibleNamespacesStart
188
+ savedPrevVisibleNamespacesEnd = @prevVisibleNamespacesEnd
189
+ savedVisibleNamespacesSize = @visibleNamespaces.size()
190
+ state = @state
191
+ state = INSIDE_DOC_ELEMENT if (visible && state == BEFORE_DOC_ELEMENT)
192
+ @res = @res + "<" + node.expanded_name() if (visible)
193
+ write_namespace_axis(node, visible)
194
+ write_attribute_axis(node)
195
+ @res = @res + ">" if (visible)
196
+ node.each_child{|child|
197
+ write_node(child)
198
+ }
199
+ @res = @res + "</" +node.expanded_name() + ">" if (visible)
200
+ @state = AFTER_DOC_ELEMENT if (visible && state == BEFORE_DOC_ELEMENT)
201
+ @prevVisibleNamespacesStart = savedPrevVisibleNamespacesStart
202
+ @prevVisibleNamespacesEnd = savedPrevVisibleNamespacesEnd
203
+ @visibleNamespaces.slice!(savedVisibleNamespacesSize, @visibleNamespaces.size() - savedVisibleNamespacesSize) if (@visibleNamespaces.size() > savedVisibleNamespacesSize)
204
+ end
205
+
206
+ def write_namespace_axis(node, visible)
207
+ doc = node.document()
208
+ has_empty_namespace = false
209
+ list = Array.new()
210
+ cur = node
211
+ #while ((cur != nil) && (cur != doc) && (cur.node_type() != :document))
212
+ namespaces = cur.node_namespaces()
213
+ namespaces.each{|prefix|
214
+ next if ((prefix == "xmlns") && (node.namespace(prefix) == ""))
215
+ namespace = cur.namespace(prefix)
216
+ next if (is_namespace_node(namespace))
217
+ next if (node.namespace(prefix) != cur.namespace(prefix))
218
+ next if (prefix == "xml" && namespace == "http://www.w3.org/XML/1998/namespace")
219
+ next if (!is_node_visible(cur))
220
+ rendered = is_namespace_rendered(prefix, namespace)
221
+ @visibleNamespaces.push(NamespaceNode.new("xmlns:"+prefix,namespace)) if (visible)
222
+ if ((!rendered) && !list.include?(prefix))
223
+ list.push(prefix)
224
+ end
225
+ has_empty_namespace = true if (prefix == nil)
226
+ }
227
+ if (visible && !has_empty_namespace && !is_namespace_rendered(nil, nil))
228
+ @res = @res + ' xmlns=""'
229
+ end
230
+ #TODO: ns of inclusive_list
231
+ #=begin
232
+ if ((@prefix_list) && (node.to_s() == node.parent().to_s()))
233
+ #list.push(node.prefix())
234
+ @inclusive_namespaces.each{|ns|
235
+ prefix = ns.prefix().split(":")[1]
236
+ list.push(prefix) if (!list.include?(prefix) && (!node.attributes.prefixes.include?(prefix)))
237
+ }
238
+ @prefix_list = nil
239
+ end
240
+ #=end
241
+ list.sort!()
242
+ list.each{|prefix|
243
+ next if (prefix == "")
244
+ next if (@rendered_prefixes.include?(prefix))
245
+ @rendered_prefixes.push(prefix)
246
+ ns = node.namespace(prefix)
247
+ ns = @preserve_element.namespace(prefix) if (ns == nil)
248
+ @res = @res + normalize_string(" " + prefix + '="' + ns + '"', NODE_TYPE_TEXT) if (prefix == "xmlns")
249
+ @res = @res + normalize_string(" xmlns:" + prefix + '="' + ns + '"', NODE_TYPE_TEXT) if (prefix != nil && prefix != "xmlns")
250
+ }
251
+ if (visible)
252
+ @prevVisibleNamespacesStart = @prevVisibleNamespacesEnd
253
+ @prevVisibleNamespacesEnd = @visibleNamespaces.size()
254
+ end
255
+ end
256
+
257
+ def write_attribute_axis(node)
258
+ list = Array.new()
259
+ node.attributes().each_attribute{|attr|
260
+ list.push(attr) if (!is_namespace_node(attr.value()) && !is_namespace_decl(attr)) # && is_node_visible(
261
+ }
262
+ if (!@exclusive && node.parent() != nil && node.parent().parent() != nil)
263
+ cur = node.parent()
264
+ while (cur != nil)
265
+ #next if (cur.attributes() == nil)
266
+ cur.each_attribute{|attribute|
267
+ next if (attribute.prefix() != "xml")
268
+ next if (attribute.prefix().index("xmlns") == 0)
269
+ next if (node.namespace(attribute.prefix()) == attribute.value())
270
+ found = true
271
+ list.each{|n|
272
+ if (n.prefix() == "xml" && n.value() == attritbute.value())
273
+ found = true
274
+ break
275
+ end
276
+ }
277
+ next if (found)
278
+ list.push(attribute)
279
+ }
280
+ end
281
+ end
282
+ list.each{|attribute|
283
+ if (attribute != nil)
284
+ if (attribute.name() != "xmlns")
285
+ @res = @res + " " + normalize_string(attribute.to_string(), NODE_TYPE_ATTRIBUTE).gsub("'",'"')
286
+ end
287
+ # else
288
+ # @res = @res + " " + normalize_string(attribute.name()+'="'+attribute.to_s()+'"', NODE_TYPE_ATTRIBUTE).gsub("'",'"')
289
+ #end
290
+ end
291
+ }
292
+ end
293
+
294
+ def is_namespace_node(namespace_uri)
295
+ return (namespace_uri == "http://www.w3.org/2000/xmlns/")
296
+ end
297
+
298
+ def is_namespace_rendered(prefix, uri)
299
+ is_empty_ns = prefix == nil && uri == nil
300
+ if (is_empty_ns)
301
+ start = 0
302
+ else
303
+ start = @prevVisibleNamespacesStart
304
+ end
305
+ @visibleNamespaces.each{|ns|
306
+ if (ns.prefix() == "xmlns:"+prefix.to_s() && ns.uri() == uri)
307
+ return true
308
+ end
309
+ }
310
+ return is_empty_ns
311
+ #(@visibleNamespaces.size()-1).downto(start) {|i|
312
+ # ns = @visibleNamespaces[i]
313
+ # return true if (ns.prefix() == "xmlns:"+prefix.to_s() && ns.uri() == uri)
314
+ # #p = ns.prefix() if (ns.prefix().index("xmlns") == 0)
315
+ # #return ns.uri() == uri if (p == prefix)
316
+ #}
317
+ #return is_empty_ns
318
+ end
319
+
320
+ def is_node_visible(node)
321
+ return true if (@xnl.size() == 0)
322
+ @xnl.each{|element|
323
+ return true if (element == node)
324
+ }
325
+ return false
326
+ end
327
+
328
+ def normalize_string(input, type)
329
+ sb = ""
330
+ return input
331
+ end
332
+ #input.each_byte{|b|
333
+ # if (b ==60 && (type == NODE_TYPE_ATTRIBUTE || is_text_node(type)))
334
+ # sb = sb + "&lt;"
335
+ # elsif (b == 62 && is_text_node(type))
336
+ # sb = sb + "&gt;"
337
+ # elsif (b == 38 && (is_text_node(type) || is_text_node(type))) #Ampersand
338
+ # sb = sb + "&amp;"
339
+ # elsif (b == 34 && is_text_node(type)) #Quote
340
+ # sb = sb + "&quot;"
341
+ # elsif (b == 9 && is_text_node(type)) #Tabulator
342
+ # sb = sb + "&#x9;"
343
+ # elsif (b == 11 && is_text_node(type)) #CR
344
+ # sb = sb + "&#xA;"
345
+ # elsif (b == 13 && (type == NODE_TYPE_ATTRIBUTE || (is_text_node(type) && type != NODE_TYPE_WHITESPACE) || type == NODE_TYPE_COMMENT || type == NODE_TYPE_PI))
346
+ # sb = sb + "&#xD;"
347
+ # elsif (b == 13)
348
+ # next
349
+ # else
350
+ # sb = sb.concat(b)
351
+ # end
352
+ #}
353
+ #sb
354
+ #end
355
+
356
+ def write_text_node(node, visible)
357
+ if (visible)
358
+ @res = @res + normalize_string(node.value(), node.node_type())
359
+ end
360
+ end
361
+
362
+ def white_text?(text)
363
+ return true if ((text.strip() == "") || (text.strip() == nil))
364
+ return false
365
+ end
366
+
367
+ def is_namespace_decl(attribute)
368
+ #return true if (attribute.name() == "xmlns")
369
+ return true if (attribute.prefix().index("xmlns") == 0)
370
+ return false
371
+ end
372
+
373
+ def is_text_node(type)
374
+ return true if (type == NODE_TYPE_TEXT || type == NODE_TYPE_CDATA || type == NODE_TYPE_WHITESPACE)
375
+ return false
376
+ end
377
+
378
+ def remove_whitespace(string)
379
+ new_string = ""
380
+ in_white = false
381
+ string.each_byte{|b|
382
+ #if (in_white && b == 32)
383
+ #else
384
+ if !(in_white && b == 32)
385
+ new_string = new_string + b.chr()
386
+ end
387
+ if (b == 62) #>
388
+ in_white = true
389
+ end
390
+ if (b == 60) #<
391
+ in_white = false
392
+ end
393
+ }
394
+ new_string
395
+ end
396
+ end
397
+
398
+ def logging=(state)
399
+ if (state)
400
+ @logger = Logger.new("xmlcanonicalizer")
401
+ @logger.level = DEBUG
402
+ @logger.trace = false
403
+ p = PatternFormatter.new(:pattern => "[%l] %d :: %.100m %15t")
404
+ @logger.add(FileOutputter.new("wss4r", {:filename => "xmlcanonicalizer.log", :formatter => BasicFormatter}))
405
+ else
406
+ @logger = nil
407
+ end
408
+ end
409
+ end #Util
410
+ end #XML
411
+
412
+
413
+ if __FILE__ == $0
414
+ document = Document.new(File.new(ARGV[0]))
415
+ body = nil
416
+ c = WSS4R::Security::Util::XmlCanonicalizer.new(false, true)
417
+
418
+ if (ARGV.size() == 3)
419
+ body = ARGV[2]
420
+ if (body == "true")
421
+ element = XPath.match(document, "/soap:Envelope/soap:Body")[0]
422
+ element = XPath.first(document, "/soap:Envelope/soap:Header/wsse:Security/Signature/SignedInfo")
423
+ result = c.canonicalize_element(element)
424
+ puts("-----")
425
+ puts(result)
426
+ puts("-----")
427
+ puts(result.size())
428
+ puts("-----")
429
+ puts(CryptHash.new().digest_b64(result))
430
+ end
431
+ else
432
+ result = c.canonicalize(document)
433
+ end
434
+
435
+ file = File.new(ARGV[1], "wb")
436
+ file.write(result)
437
+ file.close()
438
+ end
metadata CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: XMLCanonicalizer
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.1"
7
- date: 2007-05-11 00:00:00 +02:00
6
+ version: 1.0.1
7
+ date: 2007-05-29 00:00:00 +02:00
8
8
  summary: Implementation of w3c xml canonicalizer standart.
9
9
  require_paths:
10
10
  - lib
11
11
  email: Roland.Schmitt@web.de
12
- homepage: http://www.rubyforge.org/projects/c14n-r
12
+ homepage: http://www.rubyforge.org/projects/xmlcanonicalizer
13
13
  rubyforge_project:
14
14
  description:
15
15
  autorequire: xmlanonicalizer
@@ -33,6 +33,7 @@ files:
33
33
  - lib/xmlcanonicalizer.rb
34
34
  - lib/xml/util
35
35
  - lib/xml/util/xmlcanonicalizer.rb
36
+ - lib/xml/util/xmlcanonicalizer.rb~
36
37
  - README
37
38
  test_files: []
38
39