wss4r 0.5

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 (39) hide show
  1. data/README +300 -0
  2. data/lib/wss4r/aws/utils.rb +37 -0
  3. data/lib/wss4r/config/config.rb +105 -0
  4. data/lib/wss4r/rpc/proxy.rb +26 -0
  5. data/lib/wss4r/rpc/router.rb +46 -0
  6. data/lib/wss4r/rpc/wssdriver.rb +19 -0
  7. data/lib/wss4r/security/crypto/certificate.rb +21 -0
  8. data/lib/wss4r/security/crypto/cipher.rb +161 -0
  9. data/lib/wss4r/security/crypto/hash.rb +35 -0
  10. data/lib/wss4r/security/exceptions/exceptions.rb +62 -0
  11. data/lib/wss4r/security/resolver.rb +23 -0
  12. data/lib/wss4r/security/security.rb +148 -0
  13. data/lib/wss4r/security/util/hash_util.rb +39 -0
  14. data/lib/wss4r/security/util/names.rb +38 -0
  15. data/lib/wss4r/security/util/namespaces.rb +21 -0
  16. data/lib/wss4r/security/util/reference_elements.rb +15 -0
  17. data/lib/wss4r/security/util/soap_parser.rb +73 -0
  18. data/lib/wss4r/security/util/transformer_factory.rb +29 -0
  19. data/lib/wss4r/security/util/types.rb +25 -0
  20. data/lib/wss4r/security/util/xmlcanonicalizer.rb +427 -0
  21. data/lib/wss4r/security/util/xmlutils.rb +58 -0
  22. data/lib/wss4r/security/xml/encrypted_data.rb +110 -0
  23. data/lib/wss4r/security/xml/encrypted_key.rb +74 -0
  24. data/lib/wss4r/security/xml/key_info.rb +52 -0
  25. data/lib/wss4r/security/xml/reference.rb +53 -0
  26. data/lib/wss4r/security/xml/reference_list.rb +24 -0
  27. data/lib/wss4r/security/xml/security.rb +92 -0
  28. data/lib/wss4r/security/xml/signature.rb +69 -0
  29. data/lib/wss4r/security/xml/signature_value.rb +26 -0
  30. data/lib/wss4r/security/xml/signed_info.rb +83 -0
  31. data/lib/wss4r/security/xml/timestamp.rb +47 -0
  32. data/lib/wss4r/security/xml/tokentypes.rb +180 -0
  33. data/lib/wss4r/server/wssstandaloneserver.rb +27 -0
  34. data/lib/wss4r/soap/processor.rb +92 -0
  35. data/lib/wss4r/tokenresolver/authenticateuserresolver.rb +34 -0
  36. data/lib/wss4r/tokenresolver/certificateresolver.rb +62 -0
  37. data/lib/wss4r/tokenresolver/databaseresolver.rb +56 -0
  38. data/lib/wss4r/tokenresolver/resolver.rb +13 -0
  39. metadata +95 -0
data/README ADDED
@@ -0,0 +1,300 @@
1
+ == WSS4R
2
+
3
+ Project home: www.rubyforge.org/projects/wss4r
4
+ Author : Roland Schmitt, roland.schmitt@web.de
5
+ Date : 15.10.2007
6
+
7
+ Version : 0.5
8
+
9
+ For a list of changes see "CHANGELOG".
10
+
11
+ = Contents
12
+ 1. What is it (and what is it not)
13
+ 2. Requirements
14
+ 3. Installation
15
+ 4. Usage
16
+ 4.1. Resolver
17
+ 4.2. UsernameToken
18
+ 4.3. Encryption
19
+ 4.4. Signature
20
+ 4.5. Signature/Encryption
21
+ 4.6. Interoperability with WSE 2.0
22
+ 4.7. Interoperability with JWSDP 2.0
23
+ 4.8. Integration into rails
24
+ 5. Samples
25
+ 5.1. A simple example
26
+ 5.2. Rails example
27
+ 6. License
28
+ 7. Support
29
+ 8. URLs
30
+
31
+
32
+
33
+ = 1. What is it (and what is it not)
34
+ WSS4R (Web Service Security For Ruby) is a library that implements some of the
35
+ standards for web service security defined by the oasis open consortium [1].
36
+ It is a proof of concept (or "Can i do it with ruby?") and not an fully featured
37
+ implementation, so it's focussed on the encryption and signature aspects of
38
+ web services. WSS4R sits on top of the famous soap4r library of NAKAMURA Hiroshi [2],
39
+ so implementing servers or clients that uses data encryption or signatures is easy
40
+ when you know how to use soap4r.
41
+ Besides that there is a integration into the rails [3] application server, so you
42
+ can use the features of WSS4R in rails driven web services.
43
+
44
+ I've tested WSS4R with the following counterparts:
45
+ - Web Service Enhancements 2.0 [8]
46
+ - Java Web Service Development Pack 2.0 [9]
47
+
48
+
49
+ WSS4R is my first ruby project, so it is not very ruby like in most places nor is it
50
+ a example of good ruby programming in general. It was started mostly to learn ruby,
51
+ not to implement an full featured WS-Security conform library.
52
+
53
+ If you like it or hate it or want more features, drop me an email at Roland.Schmitt@web.de.
54
+
55
+
56
+ = 2. Requirements
57
+ - Ruby [4] with compiled bindings to openssl [6]
58
+ (tested with Ruby 1.8.5 and 1.8.6)
59
+
60
+ Optional (for the examples):
61
+ - Rails [3]
62
+ (tested with version 1.0.0)
63
+ - Sqlite3-Ruby [7]
64
+ (tested with version 1.1.0)
65
+
66
+ = 3. Installation
67
+ Simply do (in the root folder)
68
+
69
+ ruby setup.rb
70
+
71
+
72
+ = 4. Usage
73
+ To use WSS4R, one have to require the new driver class
74
+
75
+ require "wss4r/rpc/driver"
76
+
77
+ instead of
78
+ require "soap/rpc/driver"
79
+
80
+
81
+ = 4.1. Resolver
82
+ Resolver objects are used to find certificates, keys and to authenticate users.
83
+ Resolver objects know how to get the corresponding private key for a certificate or how to load
84
+ a certificate identified by a name.
85
+ For example, when a client sends a encrypted request to the server, there is only the certificate
86
+ embedded in the message. A resolver object is responsible for loading the private key of the
87
+ certificate.
88
+
89
+ There two implementations of resolvers:
90
+ - CertificateDirectoryResolver
91
+ Loads keys/certificates from files in a specified directory in the file system.
92
+
93
+ - DatabaseResolver
94
+ Loads keys/certificates from sqlite3 databases.
95
+
96
+
97
+ = 4.2. UsernameToken
98
+ Example:
99
+
100
+ ...
101
+ driver = Driver.new('http://localhost:8070/','urn:multiply')
102
+ driver.add_method('multiply','a','b')
103
+ ...
104
+ usernametoken = UsernameToken.new("username", "password")
105
+ driver.security().add_security_token(usernametoken)
106
+ ...
107
+
108
+ The client is authenticated with his username and password. The password is not sended as clear
109
+ text, instead a hash function is used.
110
+
111
+
112
+ = 4.3. Encryption
113
+ Example:
114
+
115
+ ...
116
+ resolver = CertificateDirectoryResolver.new("../certs/ca")
117
+ certificate = resolver.certificate_by_subject("/C=DE/ST=Rheinland-Pfalz/L=Trier/O=FF/OU=Development/CN=Server/emailAddress=server@web.de")
118
+ x509 = X509SecurityToken.new(certificate)
119
+ enc_data = EncryptedData.new(x509)
120
+ driver.security().add_security_token(enc_data)
121
+ ...
122
+
123
+ The soap body is encrypted with the TripleDES algorithm. The used encryption key is then
124
+ encrypted with the certificates public key and placed in the soap header.
125
+
126
+ Actually only TripleDES and AES are supported by WSS4R as encryption algorithms. To use AES instead of the default
127
+ TripleDES, set:
128
+ enc_data.sessionkey_algorithm=Types::ALGORITHM_AES_CBC (for 256 bit encryption) or
129
+ enc_data.sessionkey_algorithm=Types::ALGORITHM_AES128_CBC (for 128 bit encryption)
130
+
131
+ = 4.4. Signature
132
+ Example:
133
+
134
+ ...
135
+ sign_cert = OpenSSL::X509::Certificate.new(File.read("../certs/wse/wse-client.cer"))
136
+ pkey = OpenSSL::PKey::RSA.new(File.read("../certs/wse/wse-client.key"))
137
+ x509 = X509SecurityToken.new(sign_cert, pkey)
138
+ signature = Signature.new(x509)
139
+ driver.security().add_security_token(signature)
140
+ ...
141
+
142
+ The soap body and the soap header timestamp elements are signed with the supplied certificate. The signature
143
+ is embedded in the soap header.
144
+
145
+
146
+ = 4.5. Signature/Encryption
147
+ Example:
148
+
149
+ ...
150
+ resolver = CertificateDirectoryResolver.new("../certs/wse")
151
+ driver.security().add_security_resolver(resolver)
152
+ sign_cert = OpenSSL::X509::Certificate.new(File.read("../certs/wse/wse-client.cer"))
153
+ pkey = OpenSSL::PKey::RSA.new(File.read("../certs/wse/wse-client.key"))
154
+ x509 = X509SecurityToken.new(sign_cert, pkey)
155
+ signature = Signature.new(x509)
156
+ driver.security().add_security_token(signature)
157
+ encrypt_cert = OpenSSL::X509::Certificate.new(File.read("../certs/wse/wse-server.cer"))
158
+ x509 = X509SecurityToken.new(encrypt_cert)
159
+ enc_data = EncryptedData.new(x509)
160
+ enc_data.sessionkey_algorithm=(Types::ALGORITHM_AES_CBC)
161
+ driver.security().add_security_token(enc_data)
162
+ ...
163
+
164
+ You can combine signature and encryption. In most cases, for encryption the clients certificate is used and
165
+ for signature the certificate of the server.
166
+ If you first apply the encryption, the signature is generated over the encrypted data. When signing is the first step, the
167
+ the signature is generated from the plain content. So it is important to know which token is first added to the driver object.
168
+
169
+
170
+ = 4.6. Interoperability with WSE 2.0
171
+ Should work with usernames, encryption and signatures.
172
+ Sample Visual Studio projects are provided in examples/WebServiceTest (client) and examples/WebService (server).
173
+
174
+
175
+ = 4.7. Interoperability with JWSDP 2.0
176
+ Should work with usernames, encryption and signatures.
177
+ Per default the examples the JWSDP works with keyIdendifiers for finding certificates and keys.
178
+ WSS4R does not support the keyIdentifier mechanism to identify certificates, because it is not defined by oasis group.
179
+
180
+
181
+ = 4.8. Integration into rails
182
+ To use WSS4R in rails one have to modify the controller that implements the web service:
183
+
184
+ require "wss4r/aws/utils"
185
+ require "activerecordresolver"
186
+
187
+ class SimpleServiceController < ApplicationController
188
+ wsdl_service_name 'SimpleService'
189
+ web_service_scaffold :invoke
190
+ web_service_api SimpleServiceApi
191
+
192
+ wss_add_resolvers([ActiveRecordResolver.new()])
193
+
194
+
195
+ I've only tested the direct dispatching mode of action web service with WSS4R.
196
+
197
+
198
+ = 5. Examples
199
+ All examples are placed in the examples subfolder.
200
+
201
+ certs Folder with various certificates and keys for the different examples
202
+ |-- ca Generated certificates and keys for the WSS4R examples
203
+ |-- jwsdp_15 Certificates and keys for to use with the JWSDP 1.5
204
+ |-- jwsdp_16 Certificates and keys for to use with the JWSDP 1.6/2.0
205
+ |-- wse Certificates and keys for to use with the WSE 2.0
206
+
207
+ clients
208
+ PlainNET.rb Example for using a .NET web service without web service security features.
209
+ PlainXWS.rb Example for using a JWSDP web service without web service security features.
210
+ TestNET.rb Example for using a WSE 2.0 web service. Shows usenametoken, encryption and signature.
211
+ Client for the project in the WebService folder.
212
+ TestXWS.rb Example for using a JWSDP 2.0 web service. Shows usenametoken, encryption and signature.
213
+ Client for the examples bundled with the JWSDP 2.0 package. The service is found in
214
+ %JWSDP_HOME%/xws-security/samples/simple. To work, set the the keyReferenceType in the
215
+ JWSDP xml config files under config/ to "Direct".
216
+ TestWSS4R.rb Example for using a WSS4R/soap4r web service. Shows usenametoken, encryption and signature.
217
+ Used with the server in the server folder.
218
+
219
+ rails
220
+ |-- simple Example for rails integration. Requires sqlite3-ruby.
221
+ |-- client Test client for the rails web service.
222
+ |-- app Files for the web service
223
+ |-- controllers Implementration of the web service and setup for the resolver, encryption and signing.
224
+ |-- helpers Resolver implementation that uses ActiveRecord to load certificates and keys.
225
+ |-- databases Sqlite3 database with certificates and keys.
226
+
227
+ server
228
+ |-- TestServer.rb WebRick server using soap4r and WSS4R.
229
+
230
+ WebService Visual Studio project for a WSE 2.0 enabled web service. Created with Visual Studio 2003 and
231
+ C#.
232
+
233
+ WebServiceTest Visual Studio project with clients for the WebService project and for the rails example. Created with
234
+ Visual Studio 2003 and C#.
235
+
236
+
237
+ = 5.1. A simple example
238
+ At the command line, go to examples/server and type:
239
+
240
+ ruby TestServer.rb user
241
+
242
+ A WebRick server starts that requires a username/password from the client, where the password is the username reversed.
243
+ In another shell, change the working dir to examples/clients and type:
244
+
245
+ ruby TestWSS4R.rb user
246
+
247
+ It show the result of the multiplication of the 2 arguments. The client uses "Ron" as username and "noR" as password. Setting
248
+ the password to other values than "noR" in the TestWSS4R.rb file results in a "User not authenticatd!" message.
249
+
250
+ Stop the TestServer with CTRL-Z (or CTRL-C). Restart it with
251
+
252
+ ruby TestServer.rb enc sign
253
+
254
+ The server now will first encrypt any request, then signing it.
255
+
256
+ Start the client by typing:
257
+
258
+ ruby TestClient.rb sign enc
259
+
260
+ The client first signs the request, then encrypts it and shows the response.
261
+
262
+ You can use various monitoring tools like the tcpmon utility from the axis project [10] to view the
263
+ resulting request/response messages.
264
+
265
+ = 5.2. Rails example
266
+ Go to examples/rails/simple and type
267
+
268
+ ruby script/server
269
+
270
+ To start the client, open a new shell and go to examples/rails/simple/client.
271
+
272
+ ruby client.rb
273
+
274
+ The output shows the reversed string that the client sents to the server. The client signs his request and the server encrypts
275
+ and signs the response.
276
+
277
+
278
+ = 6. License
279
+
280
+ WSS4R is licensed under GPL and Ruby's custom license. See GPL and RUBYS.
281
+
282
+
283
+ = 7. Support
284
+
285
+ The RubyForge mailing list is at www.rubyforge.org/projects/wss4r.
286
+
287
+ Or, to contact the author, send mail to Roland.Schmitt@web.de
288
+
289
+
290
+ = 8. URLs
291
+ [1] - http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss
292
+ [2] - http://dev.ctor.org/soap4r/
293
+ [3] - http://www.rubyonrails.org
294
+ [4] - http://www.ruby-lang.org
295
+ [5] - http://log4r.sourceforge.net/
296
+ [6] - http://www.openssl.org
297
+ [7] - http://rubyforge.org/projects/sqlite-ruby/
298
+ [8] - http://msdn.microsoft.com/webservices/webservices/building/wse/default.aspx
299
+ [9] - https://jwsdp.dev.java.net/
300
+ [10] - http://ws.apache.org/axis/
@@ -0,0 +1,37 @@
1
+ require "wss4r/soap/processor"
2
+ require "wss4r/tokenresolver/resolver"
3
+ require "wss4r/tokenresolver/authenticateuserresolver"
4
+ require "wss4r/tokenresolver/certificateresolver"
5
+
6
+ include WSS4R
7
+ include WSS4R::Tokenresolver
8
+
9
+ module ActionWebService # :nodoc:
10
+ module Container # :nodoc:
11
+ module ActionController # :nodoc:
12
+ module ClassMethods
13
+ @@initialized_resolver = false
14
+ @@initialized_tokens = false
15
+ def security()
16
+ SOAP::Processor::security()
17
+ end
18
+ def wss_add_resolvers(resolvers)
19
+ if !(@@initialized_resolver)
20
+ resolvers.each{|resolver|
21
+ security().add_security_resolver(resolver)
22
+ }
23
+ @@initialized_resolver = true
24
+ end
25
+ end
26
+ def wss_add_security_tokens(tokens)
27
+ if !(@@initialized_tokens)
28
+ tokens.each{|token|
29
+ security().add_security_token(token)
30
+ }
31
+ @@initialized_tokens = true
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,105 @@
1
+ require "yaml"
2
+ require "date"
3
+
4
+
5
+ module WSS4R
6
+ module Config
7
+ class Config
8
+ attr_accessor :encrypt_certificate, :signature_certificate, :resolver
9
+
10
+ def initialize()
11
+ @encrypt_certificate = "certificate_by_subject,/C=DE/ST=Rheinland-Pfalz/L=Trier/O=FF/OU=Development/CN=Server/emailAddress=server@web.de"
12
+ @signature_certificate = "certificate_by_subject,/C=DE/ST=Rheinland-Pfalz/L=Trier/O=FF/OU=Developement/CN=Client/emailAddress=client@web.de"
13
+ @resolver = "CertificateDirectoryResolver, ../../certs/ca/"
14
+ end
15
+
16
+ def build_security(security)
17
+ resolver = create_instance(@resolver)
18
+ cert = create_call(resolver, @signature_certificate)
19
+ security.add_security_resolver(resolver)
20
+ security
21
+ end
22
+
23
+ =begin
24
+ cert = Certificate.new(File.new(@encrypt_certificate))
25
+ x509 = X509SecurityToken.new(cert)
26
+ enc_data = EncryptedData.new(x509)
27
+
28
+ sign_cert = @resolver.certificate_by_subject(SUBJECT_SERVER)
29
+ pkey = @resolver.private_key(sign_cert)
30
+ x509 = X509SecurityToken.new(sign_cert, pkey)
31
+ signature = Signature.new(x509)
32
+
33
+
34
+ @driver.get_security().add_security_token(enc_data)
35
+ =end
36
+
37
+ def create_instance(desc)
38
+ args = desc.split(",")
39
+ klass = args.shift().strip()
40
+ instance = klass+".new('" + args.shift().strip!()+"'" if (args.size() > 0)
41
+
42
+ args.each {|e|
43
+ instance = instance + ",'" + e.strip!() + "'"
44
+ }
45
+ instance = instance + ")"
46
+ obj = eval(instance)
47
+ obj
48
+ end
49
+
50
+ def create_call(obj, desc)
51
+ args = desc.split(",")
52
+ name = args.shift().strip()
53
+ meth = obj.method(name)
54
+ parameters = ""
55
+ parameters = args.shift().strip() if (args.size() > 0)
56
+
57
+ args.each {|a|
58
+ parameters = parameters + "," + a.to_s()
59
+ }
60
+ return_value = meth.call(parameters)
61
+ return_value
62
+ end
63
+ end
64
+
65
+ class Store
66
+ def initialize(file=".\\wss4r-conf.yaml")
67
+ @file = file
68
+ end
69
+
70
+ def save(config)
71
+ file = File.new(@file,"w")
72
+ YAML::dump(config, file)
73
+ file.close()
74
+ end
75
+
76
+ def load()
77
+ begin
78
+ file = File.open(@file)
79
+ config = YAML::load(file.read())
80
+ rescue Exception
81
+ return nil
82
+ end
83
+ config
84
+ end
85
+ end
86
+
87
+
88
+ end #Config
89
+ end #WSS4R
90
+
91
+
92
+ if __FILE__ == $0
93
+ require "wss4r/rpc/wssdriver"
94
+ require "wss4r/security/security"
95
+ require "wss4r/tokenresolver/certificateresolver"
96
+ include WSS4R::Tokenresolver
97
+
98
+ config = WSS4R::Config::Config.new()
99
+ config.build_security(nil)
100
+
101
+ store = WSS4R::Config::Store.new()
102
+ store.save(config)
103
+ config = store.load()
104
+ puts(config)
105
+ end
@@ -0,0 +1,26 @@
1
+ class SOAP::RPC::Proxy
2
+ def security()
3
+ if (@security == nil)
4
+ @security = WSS4R::Security::Security.new()
5
+ return @security
6
+ end
7
+ @security
8
+ end
9
+
10
+ def create_encoding_opt(hash = nil)
11
+ opt = {}
12
+ opt[:security] = @security
13
+ opt[:default_encodingstyle] = @default_encodingstyle
14
+ opt[:allow_unqualified_element] = @allow_unqualified_element
15
+ opt[:generate_explicit_type] = @generate_explicit_type
16
+ opt[:no_indent] = @options["soap.envelope.no_indent"]
17
+ opt.update(hash) if hash
18
+ opt
19
+ end
20
+
21
+ def invoke(req_header, req_body, opt = nil)
22
+ opt ||= create_options
23
+ opt[:security] = @security
24
+ route(req_header, req_body, opt, opt)
25
+ end
26
+ end