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.
- 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
|