XMLCanonicalizer 0.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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