information_card 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ # Portions of this class were inspired by the XML::Util::XmlCanonicalizer class written by Roland Schmitt
2
+
3
+ module InformationCard
4
+ include REXML
5
+
6
+ class XmlCanonicalizer
7
+ def initialize
8
+ @canonicalized_xml = ''
9
+ end
10
+
11
+ def canonicalize(element)
12
+ document = REXML::Document.new(element.to_s)
13
+
14
+ #TODO: Do we need this check?
15
+ if element.instance_of?(REXML::Element)
16
+ namespace = element.namespace(element.prefix)
17
+ if not namespace.empty?
18
+ if not element.prefix.empty?
19
+ document.root.add_namespace(element.prefix, namespace)
20
+ else
21
+ document.root.add_namespace(namespace)
22
+ end
23
+ end
24
+ end
25
+
26
+ document.each_child{ |node| write_node(node) }
27
+
28
+ @canonicalized_xml.strip
29
+ end
30
+
31
+ private
32
+
33
+ def write_node(node)
34
+ case node.node_type
35
+ when :text
36
+ write_text(node)
37
+ when :element
38
+ write_element(node)
39
+ end
40
+ end
41
+
42
+ def write_text(node)
43
+ if node.value.strip.empty?
44
+ @canonicalized_xml << node.value
45
+ else
46
+ @canonicalized_xml << normalize_whitespace(node.value)
47
+ end
48
+ end
49
+
50
+ def write_element(node)
51
+ @canonicalized_xml << "<#{node.expanded_name}"
52
+ write_namespaces(node)
53
+ write_attributes(node)
54
+ @canonicalized_xml << ">"
55
+ node.each_child{ |child| write_node(child) }
56
+ @canonicalized_xml << "</#{node.expanded_name}>"
57
+ end
58
+
59
+ def write_namespaces(node)
60
+ @processed_prefixes ||= []
61
+
62
+ prefixes = ["xmlns"] + node.prefixes.uniq
63
+
64
+ prefixes.sort!.each do |prefix|
65
+ namespace = node.namespace(prefix)
66
+
67
+ unless prefix.empty? or (prefix == 'xmlns' and namespace.empty?) or @processed_prefixes.include?(prefix)
68
+ @processed_prefixes << prefix
69
+
70
+ @canonicalized_xml << " "
71
+ @canonicalized_xml << "xmlns:" if not prefix == 'xmlns'
72
+ @canonicalized_xml << normalize_whitespace("#{prefix}=\"#{namespace}\"")
73
+ end
74
+ end
75
+ end
76
+
77
+ def write_attributes(node)
78
+ attributes = []
79
+
80
+ node.attributes.sort.each do |key, attribute|
81
+ attributes << attribute if not attribute.prefix =~ /^xmlns/
82
+ end
83
+
84
+ attributes.each do |attribute|
85
+ unless attribute.nil? or attribute.name == "xmlns"
86
+ @canonicalized_xml << " #{attribute.name}=\"#{normalize_whitespace(attribute.to_s)}\""
87
+ end
88
+ end
89
+ end
90
+
91
+ def normalize_whitespace(input)
92
+ input.gsub(/\s+/, ' ').strip
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,21 @@
1
+ require 'test_helper'
2
+
3
+ class CertificateUtilTest < Test::Unit::TestCase
4
+ include InformationCard
5
+
6
+ def setup
7
+ @cert_directory = File.join(File.dirname(__FILE__), "fixtures/certificates")
8
+ end
9
+
10
+ def test_private_key_from_certificate_subject
11
+ expected_private_key_content = File.read(File.join(@cert_directory, "test.key"))
12
+ private_key = CertificateUtil.lookup_private_key(@cert_directory, '/O=testinformationcardruby.com/CN=testinformationcardruby.com')
13
+ assert_equal expected_private_key_content, private_key.to_s
14
+ end
15
+
16
+ def test_should_raise_exception_if_certificate_not_found
17
+ assert_raises("No private key found in ./test/fixtures/certificates/ with subject not_exist") do
18
+ CertificateUtil.lookup_private_key(@cert_directory, 'not_exist')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ class ClaimTypesTest < Test::Unit::TestCase
4
+ include InformationCard
5
+
6
+ def test_map_should_return_specified_claims
7
+ expected_claims = ["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone",
8
+ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier"];
9
+ actual_claims = ClaimTypes.map([:mobile_phone, :ppid])
10
+ assert_equal_arrays(expected_claims, actual_claims) {|x,y| x <=> y}
11
+ end
12
+
13
+ def test_map_should_raise_exception_if_uknown_claim_specified
14
+ assert_raises("Undefined claim fraggles") do
15
+ ClaimTypes.map([:fraggles])
16
+ end
17
+ end
18
+
19
+ def test_map_should_throw_exception_when_no_claim_types_specified
20
+ expected_claims = [];
21
+ actual_claims = ClaimTypes.map([])
22
+ assert_equal_arrays(expected_claims, actual_claims) {|x,y| x <=> y}
23
+ end
24
+
25
+ def test_lookup_claim_by_attribute_name_and_namespace
26
+ assert_equal :given_name, ClaimTypes.lookup("http://schemas.xmlsoap.org/ws/2005/05/identity/claims", "givenname")
27
+ assert_equal :webpage, ClaimTypes.lookup("http://schemas.xmlsoap.org/ws/2005/05/identity/claims", "webpage")
28
+ end
29
+
30
+ def test_lookup_should_raise_exception_if_claim_not_found
31
+ assert_raises("Undefined claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/fraggles") do
32
+ ClaimTypes.lookup("http://schemas.xmlsoap.org/ws/2005/05/identity/claims", "fraggles")
33
+ end
34
+ end
35
+
36
+ def test_lookup_should_remove_attribute_name_from_namespace_if_present
37
+ assert_equal :email_address, ClaimTypes.lookup("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "emailaddress")
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class DecrypterTest < Test::Unit::TestCase
4
+ include InformationCard
5
+
6
+ def test_should_decrypt_encrypted_xml_token_into_saml_token
7
+ decrypter = Decrypter.new(
8
+ load_encrypted_information_card('john_smith.xml'),certificates_directory,
9
+ '/O=testinformationcardruby.com/CN=testinformationcardruby.com')
10
+ assert_equal load_saml_token('john_smith.xml'), decrypter.decrypt
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICDzCCAXgCCQDTdQHNZKEURjANBgkqhkiG9w0BAQUFADBMMSQwIgYDVQQKExt0
3
+ ZXN0aW5mb3JtYXRpb25jYXJkcnVieS5jb20xJDAiBgNVBAMTG3Rlc3RpbmZvcm1h
4
+ dGlvbmNhcmRydWJ5LmNvbTAeFw0wNzA2MTgxNjA2MzZaFw0wODA2MTcxNjA2MzZa
5
+ MEwxJDAiBgNVBAoTG3Rlc3RpbmZvcm1hdGlvbmNhcmRydWJ5LmNvbTEkMCIGA1UE
6
+ AxMbdGVzdGluZm9ybWF0aW9uY2FyZHJ1YnkuY29tMIGfMA0GCSqGSIb3DQEBAQUA
7
+ A4GNADCBiQKBgQDkujMZdvOCE9EMyI/BJvqk5EpYdJlO+KFiROe0oDo3bdn0FtTl
8
+ pIPNoc7H1+eR5SR2LLsPnf2kw1KSfX+ZBZHvh8uqAdxl2VuxkUJv+5kIddHFB4pv
9
+ sGS6Nz4rb4sQAN1gWY4J1kE+/u3pJMuxX6rd9rnbHgpeV076tjkEoF6LcQIDAQAB
10
+ MA0GCSqGSIb3DQEBBQUAA4GBABX9MQuE96mRWw54qgID9LYYo//k3vE8NTQkjSQk
11
+ 6SYJdORS+dYb97SRV2Cs2y96SOixb1t3Cerjo6meMv9+rLeko4HNrujt8qqtvqYn
12
+ rqHVLxw5Htw532J39D9KvrZuFqbpWW9q8go5MvPT+fJDB2vkr13Jq6dpDkNdPbGa
13
+ IgLB
14
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXAIBAAKBgQDkujMZdvOCE9EMyI/BJvqk5EpYdJlO+KFiROe0oDo3bdn0FtTl
3
+ pIPNoc7H1+eR5SR2LLsPnf2kw1KSfX+ZBZHvh8uqAdxl2VuxkUJv+5kIddHFB4pv
4
+ sGS6Nz4rb4sQAN1gWY4J1kE+/u3pJMuxX6rd9rnbHgpeV076tjkEoF6LcQIDAQAB
5
+ AoGALDq5YOY4pmGwnhk2ezJPa41dtwctEjFP+9G5QJtvRoKuj93OY23RsvTkKI7e
6
+ j77Qsy1pKtbxUmgW0o8EGpISKvLou7BsMk67gcO2YJmAL/8o058tdxUNWh1dO7J0
7
+ WoUb4Iyg6AtloZ8tCGPvYjEs+/SOKIoR0eEYiz43jEtb2PECQQD4QE6e8EU3W4Nu
8
+ Y+vG0yrVd3c5d51ukJi1GLXQiusAH4fGsCsEl325ew9qSr50iPH4Y7A0+fTfSKla
9
+ ZuGfczXdAkEA693iQvKJVUNWK0UMKFBE3R6D3HmD2U2INoyfLf+UVpsHARdY4lCX
10
+ BBEcAbwnXiFF1YeJGbMRHSeUwItdQ3TkpQJBALrJsB5YzMu1OLQzzLDCLIWHqRZ9
11
+ UOBjPfNtD0hFbkKedsvhu8xtq/SGinfAm4MVk3MAlxGVTVE/2+Ugaf1Oc6UCQH7G
12
+ NuvW4pvSYolFRoCQjELxONyS75wnwRPYx2H44ikekEg03VBfEpxb+dqw39QHPDrF
13
+ 65nFlmg+MwS+o3UzagUCQFxg/17Ld8cHjjRTUD0lcsFewNzRg05QkiY58kaAivr/
14
+ rCSTkz3ukcZ2C0bC+Gzd/1aPuETx4vmJ08dL+dkovfI=
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1 @@
1
+ <enc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:enc="http://www.w3.org/2001/04/xmlenc#"><enc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"><e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /></e:EncryptionMethod><KeyInfo><o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">RHQaUreXzrKAoZio1S+r1TWUyyQ=</o:KeyIdentifier></o:SecurityTokenReference></KeyInfo><e:CipherData><e:CipherValue>J81kk3TfEevZlnuB7mqDtM4ZnQuD8lLrd+rYrQa59fezvv90BqbQy0HU1Dd2Vbep1Dl3cTEUXUYpLV0FO2UL5c/SBKw4DfJr4avmxHZfnN7l2zrFykIUyNjjX2YnRWnXqXFUVLNKt3JCM3yZi2s2gxgd8F9nqOmiiNtarfm/1D0=</e:CipherValue></e:CipherData></e:EncryptedKey></KeyInfo><enc:CipherData><enc:CipherValue>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</enc:CipherValue></enc:CipherData></enc:EncryptedData>
@@ -0,0 +1 @@
1
+ <enc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:enc="http://www.w3.org/2001/04/xmlenc#"><enc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"><e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /></e:EncryptionMethod><KeyInfo><o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">RHQaUreXzrKAoZio1S+r1TWUyyQ=</o:KeyIdentifier></o:SecurityTokenReference></KeyInfo><e:CipherData><e:CipherValue>w+M3gueh+TCDR8aT4YNZulkYH2DDOkazYlQoELJZKUzidcAptbdXZzy4Oxubmoxt8Q936vejwhv1G6d+8Vm26fsCH3+bqq3sTkmI1xVMR2t/9/7umlO+M6Eax5Hxn8rt9fNIzfF0pgPhIPBxoL51EHJbXc9+lheXN8/HPYRSGx0=</e:CipherValue></e:CipherData></e:EncryptedKey></KeyInfo><enc:CipherData><enc:CipherValue>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</enc:CipherValue></enc:CipherData></enc:EncryptedData>
@@ -0,0 +1 @@
1
+ <saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="uuid:1ae0b1c8-10f9-422c-9e96-cb41e963d892" Issuer="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" IssueInstant="2007-06-19T13:25:52.796Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:Conditions NotBefore="2007-06-19T13:25:52.796Z" NotOnOrAfter="2007-06-19T14:25:52.796Z"><saml:AudienceRestrictionCondition><saml:Audience>https://testinformationcardruby.com/signup</saml:Audience></saml:AudienceRestrictionCondition></saml:Conditions><saml:AttributeStatement><saml:Subject><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject><saml:Attribute AttributeName="givenname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Jack</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="surname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Deer</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>jdeer@email.com</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="streetaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>33 Elk Street</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="locality" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Calgary</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="stateorprovince" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Alberta</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="postalcode" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>T3H5R1</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="country" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Canada</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="homephone" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>403-999-7300</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="otherphone" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>403-999-7400</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="mobilephone" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>403-999-7500</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="dateofbirth" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>1980-06-19T06:00:00Z</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="gender" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>1</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="webpage" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>www.informationcardruby.com</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="privatepersonalidentifier" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>NZnC7eVhrZ7DD5ZBp+Cks0JTSPV/nLF3qryWiAJz9G8=</saml:AttributeValue></saml:Attribute></saml:AttributeStatement><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI="#uuid:1ae0b1c8-10f9-422c-9e96-cb41e963d892"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>sAQmArKBqwihqm20Z/H0p7UEOTg=</DigestValue></Reference></SignedInfo><SignatureValue>BNrrDCKJWmEIXUjwQTaebmTDJrw4fR9kpg4QTt963NP3J9V5Y1+s7JrWQTx19Q5X136N71XRopWNUGmgSsNLWbBhj9Z7bywBAFLSSRMGsQsHbrmr8SWwNNFZ/yq76z44wGo8+JQ9SK4rY3T0Sel9iNAXwTLGCl0vnzf0AciV/4blrw0GJhOb9rhV/isVU1+TCsqLzYJdXIijWF4QR8iLEBwkYFy03c9Y2qls0UwXdOomQLCDB3B6WAjZvMoTFH5ZYRjU0653W1FcRQDHi7/ydlMiXDhzuuVB+R/Ie/GRs6/5/GpvT8iPvMXfQdFxt5ulp0/LUQhDY1wOEGI2XcGmng==</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>zGDnSrX1KR82cmSAiwyXJsrd/X4I/1TZfPcVSXldPZPE5BX8Qs9mx4y1nlQ/as60cyhLOU28ayXGumZmkwanOs7m16yQmLEdjG+N72jbadF355QcOciVFkI5sn2zstbDJW+9dW4hNIxjyJUtkTOBIH1Vs7f6eI7X5+0L6f88sRDT7siCnNflgAe1XG7HITtx5v88AJ3kA55CHW8j0dW/imiIl9rjA7wElC9yzs/z+I9eKezqssrrmZ8Bi9sNxgXaAkpO4caw7JIQA+bjlxShTur6+5VnlKu9XUCVzkBzVmtPb9N5HCiif5wc8/9Q0JXQ9effn0/ARTsJaJcAMeQgiw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></saml:Assertion>
@@ -0,0 +1 @@
1
+ <saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="uuid:1ccdbaa7-eeca-4c1b-aacf-4622d08074b6" Issuer="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" IssueInstant="2007-06-19T05:48:52.906Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:Conditions NotBefore="2007-06-19T05:48:52.906Z" NotOnOrAfter="2007-06-19T06:48:52.906Z"><saml:AudienceRestrictionCondition><saml:Audience>https://testinformationcardruby.com/signup</saml:Audience></saml:AudienceRestrictionCondition></saml:Conditions><saml:AttributeStatement><saml:Subject><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject><saml:Attribute AttributeName="givenname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>John</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="surname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>Smith</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>jsmith@email.com</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="privatepersonalidentifier" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>bwicndBxw/6YC029oPv0NWHBbPNMDMoJLQJ6qkofJIg=</saml:AttributeValue></saml:Attribute></saml:AttributeStatement><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI="#uuid:1ccdbaa7-eeca-4c1b-aacf-4622d08074b6"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>VZkAevzI3Hj9YRG7hW5MD2n/mwg=</DigestValue></Reference></SignedInfo><SignatureValue>OV4K3XI9JvHO7ZZU6BwFpS31psaxqvj9VotrrEF68UewDbgovjJCFwB4KA50emiI/lE/urM40OaYlWy/XZflXAyMiYQJtOeSV1lXgohBZcsqgs98kXEaoHx3TN1R5y5uusZ16++Z3E3CobN6F8KS/kPP6ocDB7FhBR3rxeKqjDGRuecILONJR8pO/4jONEsG6OGEHVXYuhhH0IT+7PZNFYt5sB4NXKPfh8pEmYj37O4JvyZnvXeQ81fI4f+TRqap6Yg3DeeTxBNJ6YBHOPP7HT5juERSZHhU4rPPjUCggMq3JPCMcNZKKBTEYclE74aDJjImynWJhtpcdqpMs/k5Lw==</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>w9yuP4lSIcTT3i9VDll83AvNvsD8HpPpBSsYKH669ImXrpx7v2RzkRatn27Ebo14CA+91HNApYJ+IeshfgkHXJ0gZx5jTNJ7VsDCJ2YgdOh8J9kKx+GMLPgogm/z0KCTE41rtXB7QYHYoMvSXqn4B9y1Thb9qLvz1nQA7oLJW3j60FOF/IiujHdrFQ09NPqILnzHZpTT4/iqEFvGofPVBwjOnwEoV8PYhMjRNW+i3yKkf54LOaNta+KTQVGC26aXtDFBR4PEOXsmk7tOvEk9+mW2Zja7zWbhhElUR6EEwcqWHjHMXHVYdypPNvCaimHfDIJ3KAJXtYUMcNCHAIOHsQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></saml:Assertion>
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ class ProcessorTest < Test::Unit::TestCase
4
+ include InformationCard
5
+
6
+ def setup
7
+ Config.certificate_location = 'test/fixtures/certificates'
8
+ Config.certificate_subject = '/O=testinformationcardruby.com/CN=testinformationcardruby.com'
9
+ Config.required_claims = [:given_name, :surname, :ppid, :email_address]
10
+ end
11
+
12
+ def test_should_take_encrypted_data_and_return_a_saml_token
13
+ claims = {:given_name => 'John',
14
+ :surname => 'Smith',
15
+ :ppid => 'bwicndBxw/6YC029oPv0NWHBbPNMDMoJLQJ6qkofJIg=',
16
+ :email_address => 'jsmith@email.com'}
17
+
18
+ setup_saml_environment('john_smith.xml')
19
+ processed_token = Processor.process(load_encrypted_information_card('john_smith.xml'))
20
+ assert processed_token.valid?
21
+ assert_equal claims, processed_token.claims
22
+ end
23
+
24
+ def test_should_return_invalid_token_if_exception_occurs_during_decryption
25
+ decrypter = Object.new
26
+ decrypter.stubs(:decrypt).raises('problem with decryption')
27
+ Decrypter.stubs(:new).returns(decrypter)
28
+
29
+ token = Processor.process('invalid token')
30
+ assert token.instance_of?(InvalidToken)
31
+ assert_equal token.errors[:decryption], 'problem with decryption'
32
+ end
33
+
34
+ end
@@ -0,0 +1,165 @@
1
+ require 'test_helper'
2
+
3
+ class SamlTokenTest < Test::Unit::TestCase
4
+ include InformationCard
5
+
6
+ def setup
7
+ @valid_saml_input = setup_saml_environment('john_smith.xml')
8
+ @not_before = Time.parse('2007-06-19T05:48:52.906Z')
9
+ @not_on_or_after = Time.parse('2007-06-19T06:48:52.906Z')
10
+ Config.required_claims = {}
11
+ Config.audience_scope = :page
12
+ end
13
+
14
+ def test_should_validate_a_valid_saml_token
15
+ saml_token = SamlToken.create(@valid_saml_input)
16
+ assert saml_token.errors.empty?
17
+ assert saml_token.valid?
18
+ end
19
+
20
+ def test_should_return_claims
21
+ saml_token = SamlToken.create(@valid_saml_input)
22
+ claims = saml_token.claims
23
+ expected_claims = {:given_name => 'John', :surname => 'Smith',
24
+ :ppid => 'bwicndBxw/6YC029oPv0NWHBbPNMDMoJLQJ6qkofJIg=',
25
+ :email_address => 'jsmith@email.com'}
26
+ assert_equal(expected_claims, claims)
27
+ end
28
+
29
+ def test_should_return_claims_for_user_with_full_set_of_claims
30
+ saml_token = SamlToken.create(setup_saml_environment('jack_deer.xml'))
31
+ claims = saml_token.claims
32
+ expected_claims = {:date_of_birth=>"1980-06-19T06:00:00Z", :given_name=>"Jack",
33
+ :postal_code=>"T3H5R1", :gender=>"1", :email_address=>"jdeer@email.com",
34
+ :country=>"Canada", :webpage=>"www.informationcardruby.com",
35
+ :surname=>"Deer", :home_phone=>"403-999-7300",
36
+ :ppid=>"NZnC7eVhrZ7DD5ZBp+Cks0JTSPV/nLF3qryWiAJz9G8=",
37
+ :street_address=>"33 Elk Street", :other_phone=>"403-999-7400",
38
+ :locality=>"Calgary", :mobile_phone=>"403-999-7500",
39
+ :state_province=>"Alberta"}
40
+ assert_equal(expected_claims, claims)
41
+ end
42
+
43
+ def test_should_not_return_claims_if_token_is_invalid
44
+ invalid_saml_input = input_with_xml_element_replaced(@valid_saml_input, "SignatureValue", "invalid signature value")
45
+ saml_token = SamlToken.create(invalid_saml_input)
46
+ assert_false saml_token.valid?
47
+ assert saml_token.claims.empty?
48
+ end
49
+
50
+ def test_should_detect_invalid_digest
51
+ valid_digest = "VZkAevzI3Hj9YRG7hW5MD2n/mwg="
52
+ saml_input_with_invalid_digest = input_with_xml_element_replaced(@valid_saml_input, "DigestValue", valid_digest.reverse)
53
+ saml_token = SamlToken.create(saml_input_with_invalid_digest)
54
+ assert_false saml_token.valid?
55
+ assert_equal ["Invalid Digest for #uuid:1ccdbaa7-eeca-4c1b-aacf-4622d08074b6. Expected #{valid_digest} but was #{valid_digest.reverse}"],
56
+ saml_token.errors[:digest]
57
+ end
58
+
59
+ def test_should_detect_invalid_signature
60
+ saml_input_with_invalid_signature = input_with_xml_element_replaced(@valid_saml_input, "SignatureValue", 'invalid signature value')
61
+ saml_token = SamlToken.create(saml_input_with_invalid_signature)
62
+ assert_false saml_token.valid?
63
+ assert_equal "Invalid Signature", saml_token.errors[:signature]
64
+ end
65
+
66
+ def test_should_return_hashed_ppid_for_unique_id_if_identity_claim_is_ppid
67
+ InformationCard::Config.identity_claim = :ppid
68
+ saml_token = SamlToken.create(@valid_saml_input)
69
+ assert_equal 'c3880b5491ae25aacedbeb5d9a40d5c966d8d84d', saml_token.unique_id
70
+ end
71
+
72
+ def test_should_return_identity_claim_value_for_unique_id_if_identity_claim_is_not_ppid
73
+ InformationCard::Config.identity_claim = :email_address
74
+ saml_token = SamlToken.create(@valid_saml_input)
75
+ assert_equal 'jsmith@email.com', saml_token.unique_id
76
+ end
77
+
78
+ def test_should_detect_when_current_time_is_before_not_before_condition
79
+ Time.stubs(:now).returns(@not_before - 1)
80
+
81
+ saml_token = SamlToken.create(@valid_saml_input)
82
+ assert_false saml_token.valid?
83
+ expected_error = {:not_before => "Time is before #{@not_before}"}
84
+ assert_equal expected_error, saml_token.errors[:conditions]
85
+ end
86
+
87
+ def test_should_detect_when_current_time_is_after_not_on_or_after_condition
88
+ Time.stubs(:now).returns(@not_on_or_after + 1)
89
+
90
+ saml_token = SamlToken.create(@valid_saml_input)
91
+ assert_false saml_token.valid?
92
+ expected_error = {:not_on_or_after => "Time is on or after #{@not_on_or_after}"}
93
+ assert_equal expected_error, saml_token.errors[:conditions]
94
+ end
95
+
96
+ def test_should_detect_when_current_time_is_on_not_on_or_after_condition
97
+ Time.stubs(:now).returns(@not_on_or_after)
98
+
99
+ saml_token = SamlToken.create(@valid_saml_input)
100
+ assert_false saml_token.valid?
101
+ expected_error = {:not_on_or_after => "Time is on or after #{@not_on_or_after}"}
102
+ assert_equal expected_error, saml_token.errors[:conditions]
103
+ end
104
+
105
+ def test_should_validate_page_level_audience_restriction
106
+ saml_token = SamlToken.create(@valid_saml_input)
107
+ assert saml_token.valid?
108
+ assert saml_token.errors[:audience].nil?
109
+ end
110
+
111
+ def test_should_detect_page_level_audience_restriction_error
112
+ InformationCard::Config.audiences = ['http://website.com/page1', 'http://website.com/page2']
113
+ saml_token = SamlToken.create(@valid_saml_input)
114
+ assert_false saml_token.valid?
115
+ expected_error = "AudienceRestriction is not valid"
116
+ assert_equal expected_error, saml_token.errors[:audience]
117
+ end
118
+
119
+ def test_should_validate_site_level_audience_restriction
120
+ InformationCard::Config.audience_scope = :site
121
+ InformationCard::Config.audiences = ['https://testinformationcardruby.com']
122
+ saml_token = SamlToken.create(@valid_saml_input)
123
+ assert saml_token.valid?
124
+ assert saml_token.errors[:audience].nil?
125
+ end
126
+
127
+ def test_should_detect_site_level_audience_restriction_error
128
+ InformationCard::Config.audience_scope = :site
129
+ InformationCard::Config.audiences = ['https://someothersite.com']
130
+ saml_token = SamlToken.create(@valid_saml_input)
131
+ assert_false saml_token.valid?
132
+ expected_error = "AudienceRestriction is not valid"
133
+ assert_equal expected_error, saml_token.errors[:audience]
134
+ end
135
+
136
+ def test_should_throw_error_if_audiences_are_not_configured
137
+ InformationCard::Config.audiences = []
138
+ saml_token = SamlToken.create(@valid_saml_input)
139
+ assert_false saml_token.valid?
140
+ expected_error = "AudienceRestriction is not valid"
141
+ assert_equal expected_error, saml_token.errors[:audience]
142
+
143
+ InformationCard::Config.audiences = nil
144
+ saml_token = SamlToken.create(@valid_saml_input)
145
+ assert_false saml_token.valid?
146
+ expected_error = "AudienceRestriction is not valid"
147
+ assert_equal expected_error, saml_token.errors[:audience]
148
+ end
149
+
150
+ def test_should_detect_missing_claim
151
+ Config.required_claims = [:ppid, :mobile_phone]
152
+ saml_token = SamlToken.create(@valid_saml_input)
153
+ assert_false saml_token.valid?
154
+ expected_error = [:mobile_phone]
155
+ assert_equal expected_error, saml_token.errors[:missing_claims]
156
+ end
157
+
158
+ def test_should_detect_missing_multiple_claims
159
+ Config.required_claims = [:ppid, :mobile_phone, :postal_code]
160
+ saml_token = SamlToken.create(@valid_saml_input)
161
+ assert_false saml_token.valid?
162
+ expected_error = [:mobile_phone, :postal_code]
163
+ assert_equal expected_error, saml_token.errors[:missing_claims]
164
+ end
165
+ end
@@ -0,0 +1,73 @@
1
+ require 'test/unit'
2
+ require "rexml/document"
3
+ require File.dirname(__FILE__) + '/../lib/information_card'
4
+
5
+ require 'rubygems'
6
+ gem 'mocha'
7
+ require 'stubba'
8
+
9
+ class Test::Unit::TestCase
10
+ include REXML
11
+
12
+ def assert_false(condition)
13
+ assert !condition
14
+ end
15
+
16
+ def load_encrypted_information_card(file_name)
17
+ File.read File.join(File.dirname(__FILE__), "fixtures/encrypted_information_cards", file_name)
18
+ end
19
+
20
+ def load_saml_token(file_name)
21
+ File.read File.join(File.dirname(__FILE__), "fixtures/saml_tokens", file_name)
22
+ end
23
+
24
+ def setup_saml_environment(file_name)
25
+ saml_token = load_saml_token(file_name)
26
+
27
+ saml_doc = REXML::Document.new(saml_token)
28
+ conditions = REXML::XPath.first(saml_doc, "//saml:Conditions", "saml" => "urn:oasis:names:tc:SAML:1.0:assertion")
29
+ not_before_time = Time.parse(conditions.attributes['NotBefore'])
30
+ Time.stubs(:now).returns(not_before_time)
31
+ audiences = REXML::XPath.match(saml_doc, "//saml:AudienceRestrictionCondition/saml:Audience", {"saml" => "urn:oasis:names:tc:SAML:1.0:assertion"})
32
+ InformationCard::Config.audiences = audiences.collect {|a| a.text}
33
+ InformationCard::Config.audience_scope = :page
34
+
35
+ saml_token
36
+ end
37
+
38
+ def certificates_directory
39
+ File.join(File.dirname(__FILE__), "fixtures/certificates")
40
+ end
41
+
42
+ def input_with_xml_element_replaced(xml_string, element, text)
43
+ doc = REXML::Document.new(xml_string)
44
+ node = doc.root.find_first_recursive {|node| node.kind_of? Element and node.name == element }
45
+ node.text = text
46
+ doc.to_s
47
+ end
48
+
49
+ def assert_equal_arrays(expected, actual)
50
+ actual.sort! {|a,b| yield a, b} if block_given?
51
+ msg = "#{expected.join(',')} expected, but was \n#{actual.join(',')}"
52
+ assert_equal expected.size, actual.size, msg
53
+ assert_equal expected, actual, msg
54
+ end
55
+
56
+ def assert_raises(arg1 = nil, arg2 = nil)
57
+ expected_error = arg1.is_a?(Exception) ? arg1 : nil
58
+ expected_class = arg1.is_a?(Class) ? arg1 : nil
59
+ expected_message = arg1.is_a?(String) ? arg1 : arg2
60
+ begin
61
+ yield
62
+ fail "expected error was not raised"
63
+ rescue Test::Unit::AssertionFailedError
64
+ raise
65
+ rescue => e
66
+ raise if e.message == "expected error was not raised"
67
+ assert_equal(expected_error, e) if expected_error
68
+ assert_equal(expected_class, e.class, "Unexpected error type raised") if expected_class
69
+ assert_equal(expected_message, e.message, "Unexpected error message") if expected_message.is_a? String
70
+ assert_matched(expected_message, e.message, "Unexpected error message") if expected_message.is_a? Regexp
71
+ end
72
+ end
73
+ end