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