wss4r 0.5

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