information_card 0.1.0
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/CHANGELOG +2 -0
- data/LICENSE +27 -0
- data/README +45 -0
- data/Rakefile +35 -0
- data/lib/information_card.rb +10 -0
- data/lib/information_card/certificate_util.rb +17 -0
- data/lib/information_card/claim_types.rb +43 -0
- data/lib/information_card/config.rb +52 -0
- data/lib/information_card/decrypter.rb +53 -0
- data/lib/information_card/identity_token.rb +23 -0
- data/lib/information_card/invalid_token.rb +8 -0
- data/lib/information_card/namespaces.rb +7 -0
- data/lib/information_card/processor.rb +15 -0
- data/lib/information_card/saml_token.rb +212 -0
- data/lib/information_card/xml_canonicalizer.rb +95 -0
- data/test/certificate_util_test.rb +21 -0
- data/test/claim_types_test.rb +39 -0
- data/test/decrypter_test.rb +12 -0
- data/test/fixtures/certificates/test.crt +14 -0
- data/test/fixtures/certificates/test.key +15 -0
- data/test/fixtures/encrypted_information_cards/jack_deer.xml +1 -0
- data/test/fixtures/encrypted_information_cards/john_smith.xml +1 -0
- data/test/fixtures/saml_tokens/jack_deer.xml +1 -0
- data/test/fixtures/saml_tokens/john_smith.xml +1 -0
- data/test/processor_test.rb +34 -0
- data/test/saml_token_test.rb +165 -0
- data/test/test_helper.rb +73 -0
- data/test/xml_canonicalizer_test.rb +188 -0
- metadata +78 -0
@@ -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
|
data/test/test_helper.rb
ADDED
@@ -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
|