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
@@ -0,0 +1,58 @@
1
+ require "rexml/document"
2
+
3
+ include REXML
4
+
5
+ class REXML::Element
6
+ def index_of(e)
7
+ return -1 if (e == nil)
8
+ children = self.children()
9
+ children.each_with_index {|child, i|
10
+ return i if (child.local_name() == e.local_name())
11
+ }
12
+ return -1
13
+ end
14
+ end
15
+
16
+ class REXML::Document
17
+ def select(xpath)
18
+ #XPath.first(document, "/env:Envelope/env:Header/wsse:Security/ds:Signature")
19
+ element = XPath.first(self, xpath)
20
+ if (element != nil)
21
+ return element
22
+ end
23
+ node_path = xpath.sub("/","").split("/")
24
+
25
+ element = self
26
+
27
+ node_path.each{|expr|
28
+ element = select_element(element, expr)
29
+ if (element == nil)
30
+ return nil
31
+ end
32
+ }
33
+ element
34
+ end
35
+
36
+ def select_element(element, name)
37
+ childs = Array.new()
38
+ element.each_child{|child|
39
+ if (child.node_type() == :element)
40
+ if (child.expanded_name() == name)
41
+ childs.push(child)
42
+ return child
43
+ end
44
+ end
45
+ }
46
+ nil
47
+ end
48
+
49
+ def element_with_attribute(key, value)
50
+
51
+ end
52
+ end
53
+
54
+ if __FILE__ == $0
55
+ document = REXML::Document.new(File.new(ARGV[0]))
56
+ element = document.select("/env:Envelope/env:Header/wsse:Security/ds:Signature")
57
+ puts("selected: " + element.to_s())
58
+ end
@@ -0,0 +1,110 @@
1
+ module WSS4R
2
+ module Security
3
+ module Xml
4
+
5
+ class EncryptedData
6
+ attr_accessor :cipher_value, :ref_id, :algorithm, :sessionkey_algorithm, :security_token
7
+
8
+ def initialize(security_token=nil)
9
+ if (security_token != nil)
10
+ @security_token = security_token
11
+ end
12
+ @sessionkey_algorithm = Types::ALGORITHM_3DES_CBC
13
+ end
14
+
15
+ def unprocess(encrypted_data)
16
+ cipher_value = XPath.first(encrypted_data, "xenc:CipherData/xenc:CipherValue", {"xenc" => Namespaces::XENC})
17
+ algorithm = XPath.first(encrypted_data, "xenc:EncryptionMethod", {"xenc" => Namespaces::XENC})
18
+ ref_id = encrypted_data.attributes["Id"]
19
+ self.cipher_value=(cipher_value.text())
20
+ self.ref_id=(ref_id)
21
+ self.algorithm=(algorithm.attributes["Algorithm"])
22
+ end
23
+
24
+ def process(document)
25
+ root = document.root()
26
+ soap_ns = nil
27
+ soap_prefix = root.prefix()
28
+ root.attributes.each_attribute() {|attr|
29
+ if (attr.value() == Namespaces::S11)
30
+ soap_ns = Namespaces::S11
31
+ end
32
+ if (attr.value() == Namespaces::S12)
33
+ soap_ns = Namespaces::S12
34
+ end
35
+ }
36
+ old_soap_body = XPath.first(document, "/env:Envelope/env:Body", {SOAPParser::soap_prefix=>SOAPParser::soap_ns})
37
+ #old_soap_body = SOAPParser.part(SOAPParser::BODY)
38
+
39
+ soap_body_string = ""
40
+ if defined?(REXML::Formatters)
41
+ formatter = REXML::Formatters::Default.new
42
+ old_soap_body.each_element(){|e|
43
+ formatter.write(e, soap_body_string)
44
+ }
45
+ else
46
+ old_soap_body.each_element(){|e|
47
+ e.write(soap_body_string)
48
+ }
49
+ end
50
+ root.delete(old_soap_body)
51
+ soap_body = root.add_element(Names::BODY)
52
+ old_soap_body.attributes().each_attribute{|a|
53
+ soap_body.add_attribute(a.expanded_name(), a.value())
54
+ #puts(a.expanded_name() + " => " + a.value())
55
+ }
56
+ digest = CryptHash.new().digest_b64(soap_body.to_s()).strip()
57
+ encrypted_data = soap_body.add_element(Names::ENCRYPTED_DATA)
58
+ encrypted_data.add_namespace("xmlns:xenc", Namespaces::XENC)
59
+ @ref_id = "EncryptedContent-"+digest.to_s()
60
+ encrypted_data.add_attributes({"Type"=>Types::XENC_CONTENT, "Id"=>@ref_id})
61
+
62
+ if (@sessionkey_algorithm == Types::ALGORITHM_3DES_CBC)
63
+ symmetric_encrypter = TripleDESSymmetricEncrypter.new()
64
+ elsif (@sessionkey_algorithm == Types::ALGORITHM_AES_CBC)
65
+ symmetric_encrypter = AESSymmetricEncrypter.new()
66
+ elsif (@sessionkey_algorithm == Types::ALGORITHM_AES128_CBC)
67
+ symmetric_encrypter = AES128SymmetricEncrypter.new()
68
+ else
69
+ raise "Unsupported encryption algorithm #{@sessionkey_algorithm}"
70
+ end
71
+ encryption_method = encrypted_data.add_element(Names::ENCRYPTION_METHOD)
72
+ encryption_method.add_attribute("Algorithm", @sessionkey_algorithm)
73
+ encrypted_body = symmetric_encrypter.encrypt_to_b64(symmetric_encrypter.iv() + soap_body_string)
74
+ encrypted_key = EncryptedKey.new(@security_token, symmetric_encrypter, self)
75
+ cipher_data = encrypted_data.add_element(Names::CIPHER_DATA)
76
+ cipher_value = cipher_data.add_element(Names::CIPHER_VALUE)
77
+ cipher_value.text=(encrypted_body.gsub("\n",""))
78
+ encrypted_key.process(document)
79
+ end
80
+
81
+ def decrypt(document, encrypted_key)
82
+ if (algorithm == Types::ALGORITHM_3DES_CBC)
83
+ symmetric_encrypter = TripleDESSymmetricEncrypter.new(encrypted_key.symmetric_key())
84
+ elsif (algorithm == Types::ALGORITHM_AES_CBC)
85
+ symmetric_encrypter = AESSymmetricEncrypter.new(encrypted_key.symmetric_key())
86
+ elsif (algorithm == Types::ALGORITHM_AES128_CBC)
87
+ symmetric_encrypter = AES128SymmetricEncrypter.new(encrypted_key.symmetric_key())
88
+ else
89
+ raise "Unsupported encryption algorithm #{algorithm}"
90
+ end
91
+ raw_data = Base64.decode64(@cipher_value)
92
+ symmetric_encrypter.iv=(raw_data)
93
+ decrypted_element = symmetric_encrypter.decrypt(raw_data)
94
+ reference = encrypted_key.reference_list().uris()[0]
95
+ reference = reference[1..-1] # remove leading #
96
+ encrypted_element = XPath.first(document, "//*[@Id='"+reference+"']")
97
+ parent = encrypted_element.parent()
98
+
99
+ #document.root().delete_element("//" + Names::SECURITY)
100
+ parent.delete(encrypted_element)
101
+
102
+ new_element = Document.new(decrypted_element)
103
+ parent.add(new_element)
104
+ #puts("encrypted_data.decrypt: " + element.to_s())
105
+ end
106
+ end
107
+
108
+ end #Xml
109
+ end #Security
110
+ end #WSS4R
@@ -0,0 +1,74 @@
1
+ module WSS4R
2
+ module Security
3
+ module Xml
4
+
5
+ class EncryptedKey
6
+ attr_reader :x509security_token, :symmetric_encrypter, :symmetric_key, :reference_list
7
+
8
+ def initialize(x509security_token=nil, symmetric_encrypter=nil, encrypted_data = nil)
9
+ @x509security_token = x509security_token
10
+ @symmetric_encrypter = symmetric_encrypter
11
+ @encrypted_data = encrypted_data
12
+ @reference_list = nil
13
+ end
14
+
15
+ def unprocess(encrypted_key)
16
+ #key_info = SOAPParser.element(encrypted_key, SOAPParser::KEY_INFO)
17
+ algorithm = XPath.first(encrypted_key, "//xenc:EncryptionMethod", {"xenc" => Namespaces::XENC})
18
+ key_info_element = XPath.first(encrypted_key, "ds:KeyInfo", {"ds"=>Namespaces::DS})
19
+ key_info = KeyInfo.new(key_info_element)
20
+ resolver = WSS4R::Security::Security.new().resolver()
21
+ @reference_list = ReferenceList.new(encrypted_key.get_elements("//xenc:ReferenceList")[0])
22
+ private_key = resolver.private_key(key_info.security_token().certificate())
23
+ key_info.security_token().private_key=(private_key)
24
+
25
+ @x509security_token = key_info.security_token()
26
+
27
+ cipher_value = XPath.first(encrypted_key, "xenc:CipherData/xenc:CipherValue", {"xenc" => Namespaces::XENC})
28
+ @symmetric_key = @x509security_token.private_decrypt_b64(cipher_value.text())
29
+ end
30
+
31
+ def process(document)
32
+ #Encrypts the symmetric key with the public key from the certificate and add an EncryptedKey element to env:Body/wsse:Security
33
+ #@x509security_token.get_xml(document)
34
+ wsse_security = Security.new()
35
+ wsse_security = wsse_security.process(document)
36
+ security_token = @x509security_token.process(document)
37
+
38
+ children = wsse_security.children()
39
+ children.each{|child|
40
+ wsse_security.delete(child)
41
+ }
42
+ wsse_security.add_element(security_token)
43
+ encrypted_key = wsse_security.add_element(Names::ENCRYPTED_KEY)
44
+ children.each{|child|
45
+ wsse_security.add_element(child)
46
+ }
47
+
48
+ encrypted_key.add_namespace("xmlns:xenc", Namespaces::XENC)
49
+ document.add_namespace("xmlns:xenc", Namespaces::XENC)
50
+ encryption_method = encrypted_key.add_element(Names::ENCRYPTION_METHOD)
51
+ encryption_method.add_attribute("Algorithm", Types::ALGORITHM_RSA15)
52
+ key_info = encrypted_key.add_element(Names::KEY_INFO)
53
+ key_info.add_namespace("xmlns:ds",Namespaces::DS)
54
+ security_token_ref = key_info.add_element(Names::SECURITY_TOKEN_REFERENCE)
55
+ reference = security_token_ref.add_element("wsse:Reference")
56
+
57
+ reference.add_attribute("URI", "#"+@x509security_token.get_id())
58
+ reference.add_attribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3")
59
+ cipher_data = encrypted_key.add_element(Names::CIPHER_DATA)
60
+ cipher_value = cipher_data.add_element(Names::CIPHER_VALUE)
61
+ cipher_value.text = @x509security_token.public_encrypt_b64(@symmetric_encrypter.key()).gsub("\n","")
62
+ reference_list = encrypted_key.add_element(Names::REFERENCE_LIST)
63
+ data_reference = reference_list.add_element(Names::DATA_REFERENCE)
64
+ data_reference.add_attribute("URI", "#" + @encrypted_data.ref_id())
65
+ end
66
+
67
+ def symmetric_encrypter()
68
+ @symmetric_encrypter
69
+ end
70
+ end
71
+
72
+ end #Xml
73
+ end #Security
74
+ end #WSS4R
@@ -0,0 +1,52 @@
1
+ module WSS4R
2
+ module Security
3
+ module Xml
4
+
5
+ class KeyInfo
6
+ attr_accessor :security_token, :type, :key_identifier
7
+
8
+ KEY_IDENTIFIER = "KEY_IDENTIFIER"
9
+ REFERENCE = "REFERENCE"
10
+
11
+ def initialize(p, *type)
12
+ if (p.kind_of?(SecurityToken))
13
+ @security_token = p
14
+ if (type != nil)
15
+ @type = type
16
+ else
17
+ @type = KEY_IDENTIFIER
18
+ end
19
+ else
20
+ reference = XPath.first(p, "wsse:SecurityTokenReference/wsse:Reference", {"wsse" => Namespaces::WSSE})
21
+ @uri = reference.attribute("URI").value()[1..-1]
22
+ @value_type = reference.attribute("ValueType").value()
23
+ @ref_element = XPath.first(p.document(), "//*[@wsu:Id='"+@uri+"']")
24
+ @security_token = X509SecurityToken.new(@ref_element.text())
25
+ end
26
+ end
27
+
28
+ def get_xml(parent)
29
+ key_info = parent.add_element(Names::KEY_INFO)
30
+ security_token_ref = key_info.add_element(Names::SECURITY_TOKEN_REFERENCE)
31
+ security_token_ref.add_namespace("xmlns:wsu", Namespaces::WSU)
32
+ wsu_id = REXML::Attribute.new("wsu:Id",security_token_ref.object_id().to_s())
33
+ security_token_ref.add_attribute(wsu_id)
34
+ if (@type == "KEY_IDENTIFIER")
35
+ key_identifier = security_token_ref.add_element(Names::KEY_IDENTIFIER)
36
+ key_identifier.add_attribute("ValueType", Types::VALUE_KEYIDENTIFIER)
37
+ key_identifier.add_attribute("EncodingType", Types::ENCODING_X509V3)
38
+ key_identifier.text=(@security_token.key_identifier())
39
+ else
40
+ reference = security_token_ref.add_element(Names::REFERENCE_WSSE)
41
+ reference.add_attribute("ValueType", Types::REFERENCE_VALUETYPE_X509)
42
+ reference.add_attribute("URI", "#"+@security_token.get_id())
43
+ end
44
+ parent
45
+ end
46
+
47
+
48
+ end
49
+
50
+ end #Xml
51
+ end #Security
52
+ end #WSS4R
@@ -0,0 +1,53 @@
1
+ module WSS4R
2
+ module Security
3
+ module Xml
4
+
5
+ class Reference
6
+ attr_reader :uri
7
+
8
+ def initialize(element, prefix_list = nil)
9
+ @ref_element = nil
10
+ @transforms = Array.new()
11
+ @prefix_list = prefix_list
12
+ @uri = element.attribute("URI").to_s()[1..-1] #remove leading #
13
+
14
+ elements = XPath.match(element, "Transforms/Transform", {"ds:" => Namespaces::DS})
15
+ #element.each_element("ds:Transforms/ds:Transform"){|e|
16
+ elements.each{|e|
17
+ @transforms.push(e.attribute("Algorithm"))
18
+ }
19
+ elements = XPath.match(element, "ds:DigestMethod", {"ds" => Namespaces::DS})
20
+ #element.each_element("ds:DigestMethod"){|e|
21
+ elements.each{|e|
22
+ @digest_algorithm = e.attribute("Algorithm")
23
+ }
24
+ elements = XPath.match(element, "ds:DigestValue", {"ds" => Namespaces::DS})
25
+ #element.each_element("ds:DigestValue"){|e|
26
+ elements.each{|e|
27
+ @digest_value = e.text().strip()
28
+ }
29
+ @ref_element = XPath.first(element.document, "//*[@wsu:Id='"+@uri+"']")
30
+ end
31
+
32
+ def verify()
33
+ trans_element = nil
34
+ @transforms.each{|transform_algorithm|
35
+ transformer = TransformerFactory::get_instance(transform_algorithm)
36
+ transformer.prefix_list=(@prefix_list)
37
+ trans_element = transformer.canonicalize_element(@ref_element)
38
+ }
39
+ if (@transforms.size() == 0)
40
+ transformer = TransformerFactory::get_instance("http://www.w3.org/2001/10/xml-exc-c14n#")
41
+ transformer.prefix_list=(@prefix_list)
42
+ trans_element = transformer.canonicalize_element(@ref_element)
43
+ end
44
+ digester = DigestFactory::get_instance(@digest_algorithm.value())
45
+ digest = digester.digest_b64(trans_element)
46
+ return true if (digest == @digest_value)
47
+ false
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,24 @@
1
+ module WSS4R
2
+ module Security
3
+ module Xml
4
+
5
+ class ReferenceList
6
+ attr_reader :uris
7
+
8
+ def initialize(referencelist)
9
+ @uris = parse_reference_list(referencelist)
10
+ end
11
+
12
+ def parse_reference_list(list)
13
+ @uris = Array.new()
14
+ elements = list.get_elements("//" + Names::DATA_REFERENCE)
15
+ elements.each{|e|
16
+ @uris.push(e.attribute("URI").value())
17
+ }
18
+ @uris
19
+ end
20
+ end
21
+
22
+ end #Xml
23
+ end #Security
24
+ end #WSS4R
@@ -0,0 +1,92 @@
1
+ module WSS4R
2
+ module Security
3
+ module Xml
4
+
5
+ class Security
6
+ def initialize()
7
+ end
8
+
9
+ def process(document)
10
+ security = XPath.first(document, "/env:Envelope/env:Header/wsse:Security")#, {SOAPParser::soap_prefix=>SOAPParser::soap_ns})
11
+ return security if (security != nil)
12
+ header = XPath.first(document, "/env:Envelope/env:Header", {SOAPParser::soap_prefix=>SOAPParser::soap_ns})
13
+ security = header.add_element(Names::SECURITY, {"env:mustUnderstand"=>"1"})
14
+ security.add_namespace("xmlns:wsse", Namespaces::WSSE)
15
+ Timestamp.new().process(security)
16
+ security
17
+ end
18
+
19
+ def unprocess(document)
20
+ # Is the document signed?
21
+ #signature_element = SOAPParser.part(SOAPParser::SIGNATURE)
22
+ #wsse = XPath.first(document, "/soap:Envelope/soap:Header/wsse:Security", {"soap"=>Namespaces::SOAP})
23
+ wsse = XPath.first(document, "/env:Envelope/env:Header/wsse:Security")
24
+
25
+ timestamp = XPath.first(document, "/soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp", {"soap"=>Namespaces::SOAP, "wsse"=>Namespaces::WSSE, "wsu"=>Namespaces::WSU})
26
+ #TODO: check timestamp, if it exists
27
+ if (timestamp != nil)
28
+ t = Timestamp.new()
29
+ t.unprocess(timestamp)
30
+ t.verify()
31
+ end
32
+ signature_element = XPath.first(document, "/env:Envelope/env:Header/wsse:Security/ds:Signature", {"env"=>Namespaces::SOAP, "ds"=>Namespaces::DS})
33
+ header = XPath.first(document, "/env:Envelope/env:Header", {"env"=>Namespaces::SOAP, "ds"=>Namespaces::DS})
34
+
35
+ encrypted_key_element = SOAPParser.part(SOAPParser::ENCRYPTED_KEY)
36
+
37
+ signature_index = wsse.index_of(signature_element) || 0
38
+ encryption_index = wsse.index_of(encrypted_key_element)
39
+
40
+ if (signature_index < encryption_index)
41
+ if (signature_element != nil)
42
+ handle_signature(signature_element)
43
+ end
44
+ encrypted_key_element = SOAPParser.part(SOAPParser::ENCRYPTED_KEY)
45
+ if (encrypted_key_element != nil)
46
+ handle_encryption(document, encrypted_key_element)
47
+ end
48
+ else
49
+ encrypted_key_element = SOAPParser.part(SOAPParser::ENCRYPTED_KEY)
50
+ if (encrypted_key_element != nil)
51
+ handle_encryption(document, encrypted_key_element)
52
+ end
53
+ signature_element = XPath.first(document, "/env:Envelope/env:Header/wsse:Security/ds:Signature", {"env"=>Namespaces::SOAP, "ds"=>Namespaces::DS})
54
+ if (signature_element != nil)
55
+ handle_signature(signature_element)
56
+ end
57
+ end
58
+ #UsernameToken in the document?
59
+ usernametoken = XPath.first(document, "/env:Envelope/env:Header/wsse:Security/wsse:UsernameToken", {"env"=>Namespaces::SOAP, "ds"=>Namespaces::DS})
60
+ if (usernametoken)
61
+ handle_usernametoken(document, usernametoken)
62
+ end
63
+ end
64
+
65
+ def handle_signature(signature_element)
66
+ signature = Signature.new(nil)
67
+ signature.unprocess(signature_element)
68
+ signature.verify()
69
+ end
70
+
71
+ def handle_encryption(document, encrypted_key_element)
72
+ encrypted_key = EncryptedKey.new()
73
+ encrypted_key.unprocess(encrypted_key_element)
74
+ encrypted_data = EncryptedData.new(encrypted_key.x509security_token())
75
+ body = SOAPParser.part(SOAPParser::BODY)
76
+ encrypted_data.unprocess(body.get_elements("//xenc:EncryptedData")[0])
77
+ encrypted_data.decrypt(document, encrypted_key)
78
+ end
79
+
80
+ def handle_usernametoken(document, token)
81
+ usernametoken = UsernameToken.new()
82
+ usernametoken.unprocess(token)
83
+ resolver = WSS4R::Security::Security.new().resolver()
84
+ success = resolver.authenticate_user(usernametoken)
85
+ return true if success
86
+ raise Exception.new("User not authenticated!") if (!success)
87
+ end
88
+ end
89
+
90
+ end #Xml
91
+ end #Security
92
+ end #WSS4R