wss4r 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +300 -0
- data/lib/wss4r/aws/utils.rb +37 -0
- data/lib/wss4r/config/config.rb +105 -0
- data/lib/wss4r/rpc/proxy.rb +26 -0
- data/lib/wss4r/rpc/router.rb +46 -0
- data/lib/wss4r/rpc/wssdriver.rb +19 -0
- data/lib/wss4r/security/crypto/certificate.rb +21 -0
- data/lib/wss4r/security/crypto/cipher.rb +161 -0
- data/lib/wss4r/security/crypto/hash.rb +35 -0
- data/lib/wss4r/security/exceptions/exceptions.rb +62 -0
- data/lib/wss4r/security/resolver.rb +23 -0
- data/lib/wss4r/security/security.rb +148 -0
- data/lib/wss4r/security/util/hash_util.rb +39 -0
- data/lib/wss4r/security/util/names.rb +38 -0
- data/lib/wss4r/security/util/namespaces.rb +21 -0
- data/lib/wss4r/security/util/reference_elements.rb +15 -0
- data/lib/wss4r/security/util/soap_parser.rb +73 -0
- data/lib/wss4r/security/util/transformer_factory.rb +29 -0
- data/lib/wss4r/security/util/types.rb +25 -0
- data/lib/wss4r/security/util/xmlcanonicalizer.rb +427 -0
- data/lib/wss4r/security/util/xmlutils.rb +58 -0
- data/lib/wss4r/security/xml/encrypted_data.rb +110 -0
- data/lib/wss4r/security/xml/encrypted_key.rb +74 -0
- data/lib/wss4r/security/xml/key_info.rb +52 -0
- data/lib/wss4r/security/xml/reference.rb +53 -0
- data/lib/wss4r/security/xml/reference_list.rb +24 -0
- data/lib/wss4r/security/xml/security.rb +92 -0
- data/lib/wss4r/security/xml/signature.rb +69 -0
- data/lib/wss4r/security/xml/signature_value.rb +26 -0
- data/lib/wss4r/security/xml/signed_info.rb +83 -0
- data/lib/wss4r/security/xml/timestamp.rb +47 -0
- data/lib/wss4r/security/xml/tokentypes.rb +180 -0
- data/lib/wss4r/server/wssstandaloneserver.rb +27 -0
- data/lib/wss4r/soap/processor.rb +92 -0
- data/lib/wss4r/tokenresolver/authenticateuserresolver.rb +34 -0
- data/lib/wss4r/tokenresolver/certificateresolver.rb +62 -0
- data/lib/wss4r/tokenresolver/databaseresolver.rb +56 -0
- data/lib/wss4r/tokenresolver/resolver.rb +13 -0
- metadata +95 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
class SOAP::RPC::Router
|
2
|
+
def unmarshal(conn_data)
|
3
|
+
opt = {}
|
4
|
+
opt[:security] = @security
|
5
|
+
contenttype = conn_data.receive_contenttype
|
6
|
+
if /#{MIMEMessage::MultipartContentType}/i =~ contenttype
|
7
|
+
opt[:external_content] = {}
|
8
|
+
mime = MIMEMessage.parse("Content-Type: " + contenttype, conn_data.receive_string)
|
9
|
+
mime.parts.each do |part|
|
10
|
+
value = Attachment.new(part.content)
|
11
|
+
value.contentid = part.contentid
|
12
|
+
obj = SOAPAttachment.new(value)
|
13
|
+
opt[:external_content][value.contentid] = obj if value.contentid
|
14
|
+
end
|
15
|
+
opt[:charset] = StreamHandler.parse_media_type(mime.root.headers['content-type'].str)
|
16
|
+
env = Processor.unmarshal(mime.root.content, opt)
|
17
|
+
else
|
18
|
+
opt[:charset] = ::SOAP::StreamHandler.parse_media_type(contenttype)
|
19
|
+
env = Processor.unmarshal(conn_data.receive_string, opt)
|
20
|
+
end
|
21
|
+
charset = opt[:charset]
|
22
|
+
conn_data.send_contenttype = "text/xml; charset=\"#{charset}\""
|
23
|
+
env
|
24
|
+
end
|
25
|
+
|
26
|
+
def marshal(conn_data, env, default_encodingstyle = nil)
|
27
|
+
opt = {}
|
28
|
+
opt[:security] = @security
|
29
|
+
opt[:external_content] = nil
|
30
|
+
opt[:default_encodingstyle] = default_encodingstyle
|
31
|
+
opt[:generate_explicit_type] = @generate_explicit_type
|
32
|
+
response_string = Processor.marshal(env, opt)
|
33
|
+
conn_data.send_string = response_string
|
34
|
+
if ext = opt[:external_content]
|
35
|
+
mimeize(conn_data, ext)
|
36
|
+
end
|
37
|
+
conn_data
|
38
|
+
end
|
39
|
+
|
40
|
+
def security()
|
41
|
+
if (@security == nil)
|
42
|
+
@security = Security.new()
|
43
|
+
end
|
44
|
+
@security
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "soap/rpc/driver"
|
2
|
+
require "soap/soap"
|
3
|
+
require "soap/processor"
|
4
|
+
require "wss4r/security/security"
|
5
|
+
require "wss4r/soap/processor"
|
6
|
+
require "wss4r/rpc/proxy"
|
7
|
+
require "wss4r/rpc/router"
|
8
|
+
|
9
|
+
include SOAP
|
10
|
+
|
11
|
+
module SOAP
|
12
|
+
module RPC
|
13
|
+
class Driver
|
14
|
+
def security()
|
15
|
+
@proxy.security()
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module OpenSSL
|
2
|
+
module X509
|
3
|
+
|
4
|
+
class Certificate
|
5
|
+
def key_identifier()
|
6
|
+
ext = extensions.find {|e| e.oid == 'subjectKeyIdentifier' }
|
7
|
+
key_identifier = Base64.encode64(ext.to_der()[11..30])
|
8
|
+
return key_identifier.gsub("\n","")
|
9
|
+
end
|
10
|
+
|
11
|
+
def filename()
|
12
|
+
return @filename
|
13
|
+
end
|
14
|
+
|
15
|
+
def filename=(filename)
|
16
|
+
@filename = filename
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module WSS4R
|
2
|
+
module Security
|
3
|
+
module Crypto
|
4
|
+
|
5
|
+
class SymmetricEncrypter
|
6
|
+
def initialize(algorithm, key = nil, iv = nil)
|
7
|
+
@cipher = Cipher.new(algorithm)
|
8
|
+
@algorithm = algorithm
|
9
|
+
if (iv == nil)
|
10
|
+
@iv = @cipher.random_iv()
|
11
|
+
else
|
12
|
+
@iv = iv
|
13
|
+
end
|
14
|
+
if (key == nil)
|
15
|
+
@key = @cipher.random_key()
|
16
|
+
else
|
17
|
+
@key = key
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def encrypt_to_b64(text)
|
22
|
+
@cipher.encrypt(@key, @iv)
|
23
|
+
@cipher.key = @key
|
24
|
+
cipher = @cipher.update(text)
|
25
|
+
cipher << @cipher.final()
|
26
|
+
Base64.encode64(cipher)
|
27
|
+
end
|
28
|
+
|
29
|
+
def decrypt(text)
|
30
|
+
@cipher.decrypt(@key, @iv)
|
31
|
+
@cipher.key = @key
|
32
|
+
@cipher.iv = @iv
|
33
|
+
cipher = @cipher.update(text[8..-1])
|
34
|
+
cipher << @cipher.final()
|
35
|
+
cipher
|
36
|
+
end
|
37
|
+
|
38
|
+
def iv()
|
39
|
+
@iv
|
40
|
+
end
|
41
|
+
|
42
|
+
def key()
|
43
|
+
@key
|
44
|
+
end
|
45
|
+
|
46
|
+
def key=(key)
|
47
|
+
@key
|
48
|
+
end
|
49
|
+
|
50
|
+
def iv_b64()
|
51
|
+
Base64.encode64(@iv)
|
52
|
+
end
|
53
|
+
|
54
|
+
def key_b64()
|
55
|
+
Base64.encode64(@key)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class TripleDESSymmetricEncrypter < SymmetricEncrypter
|
60
|
+
def initialize(key = nil, iv = nil)
|
61
|
+
@cipher = Cipher.new("DES-EDE3-CBC")
|
62
|
+
if (iv == nil)
|
63
|
+
@iv = @cipher.random_iv()
|
64
|
+
else
|
65
|
+
@iv = iv
|
66
|
+
end
|
67
|
+
if (key == nil)
|
68
|
+
@key = @cipher.random_key()
|
69
|
+
else
|
70
|
+
@key = key
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def decrypt(text)
|
75
|
+
@cipher.decrypt(@key, @iv)
|
76
|
+
@cipher.key = @key
|
77
|
+
@cipher.iv = @iv
|
78
|
+
cipher = @cipher.update(text[8..-1])
|
79
|
+
cipher << @cipher.final()
|
80
|
+
cipher
|
81
|
+
end
|
82
|
+
|
83
|
+
def algorithm()
|
84
|
+
Types::ALGORITHM_3DES_CBC
|
85
|
+
end
|
86
|
+
|
87
|
+
def iv=(text_iv)
|
88
|
+
@iv = text_iv[0..7]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class AESSymmetricEncrypter < SymmetricEncrypter
|
93
|
+
def initialize(key = nil, iv = nil)
|
94
|
+
@cipher = Cipher.new(self.cipher_name)
|
95
|
+
if (iv == nil)
|
96
|
+
@iv = @cipher.random_iv()
|
97
|
+
else
|
98
|
+
@iv = iv
|
99
|
+
end
|
100
|
+
if (key == nil)
|
101
|
+
@key = @cipher.random_key()
|
102
|
+
else
|
103
|
+
@key = key
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def decrypt(text)
|
108
|
+
@cipher.decrypt(@key, @iv)
|
109
|
+
@cipher.key = @key
|
110
|
+
@cipher.iv = @iv
|
111
|
+
cipher = @cipher.update(text[16..-1])
|
112
|
+
cipher << @cipher.final()
|
113
|
+
cipher
|
114
|
+
end
|
115
|
+
|
116
|
+
def algorithm()
|
117
|
+
Types::ALGORITHM_AES_CBC
|
118
|
+
end
|
119
|
+
|
120
|
+
def cipher_name()
|
121
|
+
"AES-256-CBC"
|
122
|
+
end
|
123
|
+
|
124
|
+
def iv=(text_iv)
|
125
|
+
@iv = text_iv[0..15]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class AES128SymmetricEncrypter < AESSymmetricEncrypter
|
130
|
+
def initialize(key = nil, iv = nil)
|
131
|
+
super(key, iv)
|
132
|
+
end
|
133
|
+
|
134
|
+
def algorithm()
|
135
|
+
Types::ALGORITHM_AES128_CBC
|
136
|
+
end
|
137
|
+
|
138
|
+
def cipher_name()
|
139
|
+
"AES-128-CBC"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class AsymmetricEncrypter
|
144
|
+
def initialize(filename)
|
145
|
+
@private_key = RSA.new(File.read(filename))
|
146
|
+
end
|
147
|
+
|
148
|
+
def decrypt_symmetrickey_from_b64(text)
|
149
|
+
ciphertext = @private_rsa_key.private_decrypt(text)
|
150
|
+
iv = ciphertext[0..7]
|
151
|
+
key = ciphertext[8..-1]
|
152
|
+
symmetric_key = Cipher.new(@symmetric_algorithm)
|
153
|
+
symmetric_key.decrypt(key, iv)
|
154
|
+
symmetric_key.key = key
|
155
|
+
symmetric_key
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end #Crypto
|
160
|
+
end #Security
|
161
|
+
end #WSS4R
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "openssl"
|
2
|
+
include OpenSSL
|
3
|
+
include OpenSSL::Digest
|
4
|
+
|
5
|
+
|
6
|
+
module WSS4R
|
7
|
+
module Security
|
8
|
+
module Crypto
|
9
|
+
|
10
|
+
class CryptHash
|
11
|
+
|
12
|
+
def initialize(type = "SHA1")
|
13
|
+
@digest = SHA1.new() if (type == "SHA1")
|
14
|
+
@digest = MD5.new() if (type == "MD5")
|
15
|
+
end
|
16
|
+
|
17
|
+
def digest(value)
|
18
|
+
@digest.update(value)
|
19
|
+
return @digest.digest()
|
20
|
+
end
|
21
|
+
|
22
|
+
def digest_b64(value)
|
23
|
+
digest = self.digest(value)
|
24
|
+
return Base64.encode64(digest)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s()
|
28
|
+
return @digest.to_s()
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module WSS4R
|
2
|
+
module Security
|
3
|
+
module Exceptions
|
4
|
+
|
5
|
+
class FaultString
|
6
|
+
attr_reader :data
|
7
|
+
def initialize(data)
|
8
|
+
@data = data
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class WSS4RFault < SOAP::FaultError
|
13
|
+
attr_accessor :faultcode, :faultstring, :faultactor, :detail
|
14
|
+
|
15
|
+
def initialize(faultcode,faultstring,faultactor,detail)
|
16
|
+
@faultcode = faultcode
|
17
|
+
@faultstring = FaultString.new(faultstring)
|
18
|
+
@faultactor = faultactor
|
19
|
+
@detail = detail
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class VerificationFault < WSS4RFault
|
24
|
+
def initialize()
|
25
|
+
@faultcode = "100"
|
26
|
+
@faultstring = FaultString.new("Signature not valid!")
|
27
|
+
@faultactor = "test"
|
28
|
+
@detail = "Signature verification failed."
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class TimestampFault < WSS4RFault
|
33
|
+
def initialize()
|
34
|
+
@faultcode = "101"
|
35
|
+
@faultstring = FaultString.new("Timestamp not valid")
|
36
|
+
@faultactor = "test"
|
37
|
+
@detail = "Timestamp verification failed."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class UsernameTokenFault < WSS4RFault
|
42
|
+
def initialize()
|
43
|
+
@faultcode = "102"
|
44
|
+
@faultstring = FaultString.new("UsernameToken not valid")
|
45
|
+
@faultactor = "test"
|
46
|
+
@detail = "UsernameToken verification failed."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class NoSecurityFault < WSS4RFault
|
51
|
+
def initialize()
|
52
|
+
@faultcode = "103"
|
53
|
+
@faultstring = FaultString.new("No security token received.")
|
54
|
+
@faultactor = "test"
|
55
|
+
@detail = "No security token received."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end #WSS4R
|
60
|
+
end #Security
|
61
|
+
end #Exceptions
|
62
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Resolver < Array
|
2
|
+
def authenticate_user(usernametoken)
|
3
|
+
self.each{|r|
|
4
|
+
success = r.authenticate_user(usernametoken)
|
5
|
+
return true if (success)
|
6
|
+
}
|
7
|
+
false
|
8
|
+
end
|
9
|
+
def private_key(certificate)
|
10
|
+
self.each{|r|
|
11
|
+
key = r.private_key(certificate)
|
12
|
+
return key if (key)
|
13
|
+
}
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
def certificate_by_subject(subject)
|
17
|
+
self.each{|r|
|
18
|
+
certificate = r.certificate_by_subject(subject)
|
19
|
+
return certificate if (certificate)
|
20
|
+
}
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require "wss4r/security/xml/encrypted_key"
|
2
|
+
require "wss4r/security/xml/signature"
|
3
|
+
require "wss4r/security/xml/tokentypes"
|
4
|
+
require "wss4r/security/xml/encrypted_data"
|
5
|
+
require "wss4r/security/xml/reference_list"
|
6
|
+
require "wss4r/security/xml/security"
|
7
|
+
require "wss4r/security/xml/signed_info"
|
8
|
+
require "wss4r/security/xml/key_info"
|
9
|
+
require "wss4r/security/xml/signature_value"
|
10
|
+
require "wss4r/security/xml/reference"
|
11
|
+
require "wss4r/security/xml/timestamp"
|
12
|
+
|
13
|
+
require "wss4r/security/crypto/certificate"
|
14
|
+
require "wss4r/security/crypto/cipher"
|
15
|
+
require "wss4r/security/crypto/hash"
|
16
|
+
|
17
|
+
require "wss4r/security/util/transformer_factory"
|
18
|
+
require "wss4r/security/util/reference_elements"
|
19
|
+
require "wss4r/security/util/xmlcanonicalizer"
|
20
|
+
require "wss4r/security/util/namespaces"
|
21
|
+
require "wss4r/security/util/xmlutils"
|
22
|
+
require "wss4r/security/util/names"
|
23
|
+
require "wss4r/security/util/types"
|
24
|
+
require "wss4r/security/util/soap_parser"
|
25
|
+
require "wss4r/security/exceptions/exceptions"
|
26
|
+
|
27
|
+
require "wss4r/config/config"
|
28
|
+
require "wss4r/security/resolver"
|
29
|
+
|
30
|
+
require "time"
|
31
|
+
require "base64"
|
32
|
+
require "rexml/document"
|
33
|
+
|
34
|
+
require "soap/rpc/driver"
|
35
|
+
include SOAP
|
36
|
+
|
37
|
+
include OpenSSL
|
38
|
+
include OpenSSL::X509
|
39
|
+
include OpenSSL::Digest
|
40
|
+
include OpenSSL::Cipher
|
41
|
+
include OpenSSL::PKey
|
42
|
+
|
43
|
+
include WSS4R::Security::Xml
|
44
|
+
include WSS4R::Security::Util
|
45
|
+
include WSS4R::Security::Crypto
|
46
|
+
include WSS4R::Security::Exceptions
|
47
|
+
|
48
|
+
|
49
|
+
module WSS4R
|
50
|
+
module Security
|
51
|
+
|
52
|
+
class Security
|
53
|
+
attr_reader :tokens
|
54
|
+
|
55
|
+
@@resolver = Resolver.new()
|
56
|
+
|
57
|
+
def initialize()
|
58
|
+
@tokens = Array.new()
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_security_token(token)
|
62
|
+
@tokens.push(token)
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_security_resolver(resolver)
|
66
|
+
@@resolver.push(resolver)
|
67
|
+
end
|
68
|
+
|
69
|
+
def clear_resolver!()
|
70
|
+
@@resolver.clear()
|
71
|
+
end
|
72
|
+
|
73
|
+
def clear_tokens!()
|
74
|
+
@tokens.clear()
|
75
|
+
end
|
76
|
+
|
77
|
+
def resolver()
|
78
|
+
@@resolver
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_document_marshal(document)
|
82
|
+
return if (@tokens.size() == 0)
|
83
|
+
SOAPParser.document=(document)
|
84
|
+
|
85
|
+
document.root.add_namespace("xmlns:wsu", Namespaces::WSU)
|
86
|
+
document.root.add_namespace("xmlns:wsse", Namespaces::WSSE)
|
87
|
+
document.root.add_namespace("xmlns:wsa", Namespaces::WSA)
|
88
|
+
document.root.add_namespace("xmlns:xenc", Namespaces::XENCD)
|
89
|
+
document.root.add_namespace("xmlns:xsd", Namespaces::XSD)
|
90
|
+
document.root.add_namespace("xmlns:xsi", Namespaces::XSI)
|
91
|
+
root = document.root()
|
92
|
+
soap_prefix = nil
|
93
|
+
soap_ns=nil
|
94
|
+
root.attributes.each_attribute() {|attr|
|
95
|
+
if (attr.value() == Namespaces::S11)
|
96
|
+
soap_prefix = attr.name()
|
97
|
+
soap_ns = Namespaces::S11
|
98
|
+
end
|
99
|
+
if (attr.value() == Namespaces::S12)
|
100
|
+
soap_prefix = attr.name()
|
101
|
+
soap_ns = Namespaces::S12
|
102
|
+
end
|
103
|
+
}
|
104
|
+
SOAPParser::soap_ns=(soap_ns)
|
105
|
+
SOAPParser::soap_prefix=(soap_prefix)
|
106
|
+
|
107
|
+
soap_body = XPath.first(document, "/env:Envelope/env:Body", {SOAPParser::soap_prefix => SOAPParser::soap_ns})
|
108
|
+
|
109
|
+
#soap_body = XPath.first(document, soap_prefix+":Envelope/"+soap_prefix+":Body")
|
110
|
+
#soap_body = SOAPParser.part(SOAPParser::BODY)
|
111
|
+
return if !soap_body
|
112
|
+
root.delete_element(soap_body)
|
113
|
+
soap_header = SOAPParser.part(SOAPParser::HEADER)
|
114
|
+
if (soap_header == nil)
|
115
|
+
soap_header = root.add_element(Names::HEADER)
|
116
|
+
end
|
117
|
+
root.add_element(soap_body)
|
118
|
+
security = WSS4R::Security::Xml::Security.new()
|
119
|
+
|
120
|
+
security.process(document)
|
121
|
+
|
122
|
+
@tokens.each{|token|
|
123
|
+
token.process(document)
|
124
|
+
}
|
125
|
+
####Sort
|
126
|
+
security = XPath.first(root, "/env:Envelope/env:Header/wsse:Security")#, {SOAPParser::soap_prefix=>SOAPParser::soap_ns})
|
127
|
+
timestamp = XPath.first(security, "wsu:Timestamp")
|
128
|
+
@t = timestamp
|
129
|
+
@s = security
|
130
|
+
children = security.children()
|
131
|
+
children.each{|child|
|
132
|
+
security.delete(child)
|
133
|
+
}
|
134
|
+
children.delete(timestamp)
|
135
|
+
security.add_element(timestamp)
|
136
|
+
children.each{|child|
|
137
|
+
security.add_element(child)
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def process_document_unmarshal(document)
|
142
|
+
security = WSS4R::Security::Xml::Security.new()
|
143
|
+
security.unprocess(document)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end #Security
|
148
|
+
end #WSS4R
|