rsaml 0.1.2

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 (97) hide show
  1. data/LICENSE +0 -0
  2. data/README +13 -0
  3. data/Rakefile +136 -0
  4. data/lib/rsaml.rb +57 -0
  5. data/lib/rsaml/action.rb +57 -0
  6. data/lib/rsaml/action_namespace.rb +63 -0
  7. data/lib/rsaml/advice.rb +34 -0
  8. data/lib/rsaml/assertion.rb +192 -0
  9. data/lib/rsaml/attribute.rb +76 -0
  10. data/lib/rsaml/audience.rb +19 -0
  11. data/lib/rsaml/authentication_context.rb +34 -0
  12. data/lib/rsaml/authn_context/README +1 -0
  13. data/lib/rsaml/authn_context/authentication_context_declaration.rb +42 -0
  14. data/lib/rsaml/authn_context/identification.rb +10 -0
  15. data/lib/rsaml/authn_context/physical_verification.rb +24 -0
  16. data/lib/rsaml/condition.rb +13 -0
  17. data/lib/rsaml/conditions.rb +107 -0
  18. data/lib/rsaml/encrypted.rb +12 -0
  19. data/lib/rsaml/errors.rb +16 -0
  20. data/lib/rsaml/evidence.rb +21 -0
  21. data/lib/rsaml/ext/string.rb +5 -0
  22. data/lib/rsaml/identifier.rb +9 -0
  23. data/lib/rsaml/identifier/base.rb +23 -0
  24. data/lib/rsaml/identifier/issuer.rb +28 -0
  25. data/lib/rsaml/identifier/name.rb +55 -0
  26. data/lib/rsaml/parser.rb +23 -0
  27. data/lib/rsaml/protocol.rb +21 -0
  28. data/lib/rsaml/protocol/artifact_resolve.rb +14 -0
  29. data/lib/rsaml/protocol/assertion_id_request.rb +18 -0
  30. data/lib/rsaml/protocol/authn_request.rb +91 -0
  31. data/lib/rsaml/protocol/idp_entry.rb +18 -0
  32. data/lib/rsaml/protocol/idp_list.rb +28 -0
  33. data/lib/rsaml/protocol/message.rb +65 -0
  34. data/lib/rsaml/protocol/name_id_policy.rb +31 -0
  35. data/lib/rsaml/protocol/query.rb +12 -0
  36. data/lib/rsaml/protocol/query/attribute_query.rb +56 -0
  37. data/lib/rsaml/protocol/query/authn_query.rb +30 -0
  38. data/lib/rsaml/protocol/query/authz_decision_query.rb +40 -0
  39. data/lib/rsaml/protocol/query/subject_query.rb +22 -0
  40. data/lib/rsaml/protocol/request.rb +27 -0
  41. data/lib/rsaml/protocol/requested_authn_context.rb +34 -0
  42. data/lib/rsaml/protocol/response.rb +56 -0
  43. data/lib/rsaml/protocol/scoping.rb +33 -0
  44. data/lib/rsaml/protocol/status.rb +38 -0
  45. data/lib/rsaml/protocol/status_code.rb +84 -0
  46. data/lib/rsaml/proxy_restriction.rb +30 -0
  47. data/lib/rsaml/statement.rb +10 -0
  48. data/lib/rsaml/statement/attribute_statement.rb +27 -0
  49. data/lib/rsaml/statement/authentication_statement.rb +57 -0
  50. data/lib/rsaml/statement/authorization_decision_statement.rb +53 -0
  51. data/lib/rsaml/statement/base.rb +9 -0
  52. data/lib/rsaml/subject.rb +37 -0
  53. data/lib/rsaml/subject_confirmation.rb +35 -0
  54. data/lib/rsaml/subject_confirmation_data.rb +55 -0
  55. data/lib/rsaml/subject_locality.rb +27 -0
  56. data/lib/rsaml/validatable.rb +21 -0
  57. data/lib/rsaml/version.rb +9 -0
  58. data/lib/xml_enc.rb +3 -0
  59. data/lib/xml_sig.rb +11 -0
  60. data/lib/xml_sig/canonicalization_method.rb +43 -0
  61. data/lib/xml_sig/key_info.rb +55 -0
  62. data/lib/xml_sig/reference.rb +57 -0
  63. data/lib/xml_sig/signature.rb +29 -0
  64. data/lib/xml_sig/signature_method.rb +20 -0
  65. data/lib/xml_sig/signed_info.rb +27 -0
  66. data/lib/xml_sig/transform.rb +37 -0
  67. data/test/action_namespace_test.rb +93 -0
  68. data/test/action_test.rb +51 -0
  69. data/test/advice_test.rb +25 -0
  70. data/test/assertion_test.rb +192 -0
  71. data/test/attribute_test.rb +60 -0
  72. data/test/authentication_context_test.rb +26 -0
  73. data/test/conditions_test.rb +84 -0
  74. data/test/evidence_test.rb +33 -0
  75. data/test/identifier_test.rb +22 -0
  76. data/test/issuer_test.rb +33 -0
  77. data/test/name_test.rb +33 -0
  78. data/test/parser_test.rb +32 -0
  79. data/test/protocol/assertion_id_request_test.rb +19 -0
  80. data/test/protocol/attribute_query_test.rb +30 -0
  81. data/test/protocol/authn_query_test.rb +20 -0
  82. data/test/protocol/authn_request_test.rb +56 -0
  83. data/test/protocol/authz_decision_query_test.rb +31 -0
  84. data/test/protocol/idp_list_test.rb +15 -0
  85. data/test/protocol/request_test.rb +66 -0
  86. data/test/protocol/response_test.rb +68 -0
  87. data/test/protocol/scoping_test.rb +20 -0
  88. data/test/protocol/status_code_test.rb +34 -0
  89. data/test/protocol/status_test.rb +16 -0
  90. data/test/proxy_restriction_test.rb +20 -0
  91. data/test/rsaml_test.rb +12 -0
  92. data/test/statement_test.rb +101 -0
  93. data/test/subject_locality_test.rb +27 -0
  94. data/test/subject_test.rb +44 -0
  95. data/test/test_helper.rb +16 -0
  96. data/test/xml_sig/canonicalization_test.rb +19 -0
  97. metadata +187 -0
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class AuthzDecisionQueryTest < Test::Unit::TestCase
4
+ include RSAML::Protocol::Query
5
+
6
+ context "an authz decision query" do
7
+ setup do
8
+ @query = AuthzDecisionQuery.new(Subject.new('example'))
9
+ @query.resource = 'http://somesite/some/resource'
10
+ @query.actions << Action.new('Read')
11
+ end
12
+ should "be valid" do
13
+ assert_nothing_raised { @query.validate }
14
+ end
15
+ context "when producing xml" do
16
+ should "include a subject" do
17
+ assert_match('<saml:Subject>example</saml:Subject>', @query.to_xml)
18
+ end
19
+ should "include a Resource attribute" do
20
+ assert_match(%Q(<samlp:AuthzDecisionQuery Resource="#{@query.resource}"), @query.to_xml)
21
+ end
22
+ should "include actions" do
23
+ assert_match(%Q(<saml:Action Namespace="urn:oasis:names:tc:SAML:1.0:action:rwedc-negation">Read</saml:Action>), @query.to_xml)
24
+ end
25
+ should "optionally include evidence" do
26
+ @query.evidence = Evidence.new
27
+ assert_match(%Q(<saml:Evidence></saml:Evidence>), @query.to_xml)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class IDPListTest < Test::Unit::TestCase
4
+ include RSAML::Protocol
5
+ context "an idp list" do
6
+ setup do
7
+ @idp_list = IDPList.new
8
+ end
9
+ context "when producing xml" do
10
+ should "have the IDPList element" do
11
+ assert_match('<samlp:IDPList', @idp_list.to_xml)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RequestTest < Test::Unit::TestCase
4
+ include RSAML::Protocol
5
+ context "a request instance" do
6
+ setup do
7
+ @request = Request.new
8
+ end
9
+ should "require an id" do
10
+ @request.id = nil
11
+ assert_raise ValidationError do
12
+ @request.validate
13
+ end
14
+ end
15
+ should "require a version" do
16
+ @request.version = nil
17
+ assert_raise ValidationError do
18
+ @request.validate
19
+ end
20
+ end
21
+ should "require an issue instant" do
22
+ @request.issue_instant = nil
23
+ assert_raise ValidationError do
24
+ @request.validate
25
+ end
26
+ end
27
+ should "require an issue instant to be UTC" do
28
+ @request.issue_instant = Time.now
29
+ assert_raise ValidationError do
30
+ @request.validate
31
+ end
32
+ end
33
+ should "create a response with in_response_to set properly" do
34
+ response = @request.respond(Status.new(StatusCode::SUCCESS))
35
+ assert_not_nil response
36
+ assert_equal @request.id, response.in_response_to
37
+ end
38
+ context "when producing xml" do
39
+ should "include the samlp:Request element" do
40
+ assert_match('<samlp:Request', @request.to_xml)
41
+ end
42
+ should "require include required attributes" do
43
+ xml = @request.to_xml
44
+ assert_match(/ID="#{@request.id}"/, xml)
45
+ assert_match(/Version="2.0"/, xml)
46
+ assert_match(/IssueInstant="#{date_match}"/, xml)
47
+ end
48
+ should "optionally include a destination" do
49
+ @request.destination = 'http://somesite/destination'
50
+ assert_match(/Destination="#{@request.destination}"/, @request.to_xml)
51
+ end
52
+ should "optionally include a consent" do
53
+ @request.consent = 'http://somesite/consent'
54
+ assert_match(/Consent="#{@request.consent}"/, @request.to_xml)
55
+ end
56
+ should "optionally include an issuer child element" do
57
+ @request.issuer = Identifier::Issuer.new('example')
58
+ assert_match(%Q(<saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">example</saml:Issuer>), @request.to_xml)
59
+ end
60
+ should "optionally include a signature" do
61
+ @request.signature = XmlSig::Signature.new()
62
+ assert_match(%Q(<ds:Signature), @request.to_xml)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ResponseTest < Test::Unit::TestCase
4
+ include RSAML::Protocol
5
+ context "a response instance" do
6
+ setup do
7
+ @response = Response.new(Status.new(StatusCode::SUCCESS))
8
+ end
9
+ should "require an id" do
10
+ @response.id = nil
11
+ assert_raise ValidationError do
12
+ @response.validate
13
+ end
14
+ end
15
+ should "require a version" do
16
+ @response.version = nil
17
+ assert_raise ValidationError do
18
+ @response.validate
19
+ end
20
+ end
21
+ should "require an issue instant" do
22
+ @response.issue_instant = nil
23
+ assert_raise ValidationError do
24
+ @response.validate
25
+ end
26
+ end
27
+ should "require an issue instant to be UTC" do
28
+ @response.issue_instant = Time.now
29
+ assert_raise ValidationError do
30
+ @response.validate
31
+ end
32
+ end
33
+ should "be valid" do
34
+ assert_nothing_raised { @response.validate }
35
+ end
36
+ context "when producing xml" do
37
+ should "include the samlp:Response element" do
38
+ assert_match('<samlp:Response', @response.to_xml)
39
+ end
40
+ should "require include required attributes" do
41
+ xml = @response.to_xml
42
+ assert_match(/ID="#{@response.id}"/, xml)
43
+ assert_match(/Version="2.0"/, xml)
44
+ assert_match(/IssueInstant="#{date_match}"/, xml)
45
+ end
46
+ should "optionally include an InResponseTo attribute" do
47
+ @response.in_response_to = 'some_id'
48
+ assert_match(/InResponseTo="some_id"/, @response.to_xml)
49
+ end
50
+ should "optionally include a destination" do
51
+ @response.destination = 'http://somesite/destination'
52
+ assert_match(/Destination="#{@response.destination}"/, @response.to_xml)
53
+ end
54
+ should "optionally include a consent" do
55
+ @response.consent = 'http://somesite/consent'
56
+ assert_match(/Consent="#{@response.consent}"/, @response.to_xml)
57
+ end
58
+ should "optionally include an issuer child element" do
59
+ @response.issuer = Identifier::Issuer.new('example')
60
+ assert_match(%Q(<saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">example</saml:Issuer>), @response.to_xml)
61
+ end
62
+ should "optionally include a signature" do
63
+ @response.signature = XmlSig::Signature.new()
64
+ assert_match(%Q(<ds:Signature), @response.to_xml)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ScopingTest < Test::Unit::TestCase
4
+ include RSAML::Protocol
5
+ context "a scoping instance" do
6
+ setup do
7
+ @scoping = Scoping.new
8
+ end
9
+ context "when producing xml" do
10
+ should "optionally include a proxy count" do
11
+ @scoping.proxy_count = 2
12
+ assert_match '<samlp:Scoping ProxyCount="2"', @scoping.to_xml
13
+ end
14
+ should "optionally include an idp list" do
15
+ @scoping.idp_list = IDPList.new(IDPEntry.new('some_provider_id'))
16
+ assert_match '<samlp:IDPList><samlp:IDPEntry', @scoping.to_xml
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class StatusCodeTest < Test::Unit::TestCase
4
+ include RSAML::Protocol
5
+
6
+ context "the StatusCode class" do
7
+ should "have 4 top-level status codes" do
8
+ assert_equal 4, StatusCode.top_level_status_codes.length
9
+ end
10
+ should "have 19 second-level status codes" do
11
+ assert_equal 19, StatusCode.second_level_status_codes.length
12
+ end
13
+ should "have constants for the top-level status codes" do
14
+ assert_equal StatusCode.top_level_status_codes[:success], StatusCode::SUCCESS
15
+ assert_equal StatusCode.top_level_status_codes[:requestor], StatusCode::REQUESTOR
16
+ assert_equal StatusCode.top_level_status_codes[:responder], StatusCode::RESPONDER
17
+ assert_equal StatusCode.top_level_status_codes[:version_mismatch], StatusCode::VERSION_MISMATCH
18
+ end
19
+ end
20
+
21
+ context "a success status code instance" do
22
+ setup do
23
+ @status_code = StatusCode::SUCCESS
24
+ end
25
+ context "when producing xml" do
26
+ should "have the samlp:StatusCode element name" do
27
+ assert_match(/<samlp:StatusCode/, @status_code.to_xml)
28
+ end
29
+ should "include a value" do
30
+ assert_match(/Value="urn:oasis:names:tc:SAML:2.0:status:Success"/, @status_code.to_xml)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class StatusTest < Test::Unit::TestCase
4
+ include RSAML::Protocol
5
+
6
+ context "a status instance" do
7
+ setup do
8
+ @status = Status.new(StatusCode::SUCCESS)
9
+ end
10
+ context "when producing xml" do
11
+ should "include a status code" do
12
+ assert_match(%Q(<samlp:StatusCode Value="#{StatusCode::SUCCESS}">), @status.to_xml)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ProxyRestrictionTest < Test::Unit::TestCase
4
+ context "a proxy restriction" do
5
+ setup do
6
+ @proxy_restriction = ProxyRestriction.new
7
+ end
8
+ context "when producing xml" do
9
+ should "optionally include a count" do
10
+ @proxy_restriction.count = 1
11
+ assert_equal '<saml:ProxyRestriction Count="1"></saml:ProxyRestriction>', @proxy_restriction.to_xml
12
+ end
13
+ should "optionally include audiences" do
14
+ audience = Audience.new('some_uri')
15
+ @proxy_restriction.audiences << audience
16
+ assert_equal '<saml:ProxyRestriction><saml:Audience>some_uri</saml:Audience></saml:ProxyRestriction>', @proxy_restriction.to_xml
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ class RSAMLTest < Test::Unit::TestCase
2
+ context "the RSAML module" do
3
+ should "provide the SAML namespaces" do
4
+ assert_equal 'urn:oasis:names:tc:SAML:2.0:assertion', RSAML::saml_namespaces['saml']
5
+ assert_equal 'urn:oasis:names:tc:SAML:2.0:protocol', RSAML::saml_namespaces['samlp']
6
+ assert_equal 'http://www.w3.org/2000/09/xmldsig#', RSAML::saml_namespaces['ds']
7
+ assert_equal 'http://www.w3.org/2001/04/xmlenc#', RSAML::saml_namespaces['xenc']
8
+ assert_equal 'http://www.w3.org/2001/XMLSchema', RSAML::saml_namespaces['xs']
9
+ assert_equal 'http://www.w3.org/2001/XMLSchema-instance', RSAML::saml_namespaces['xsi']
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class StatementTest < Test::Unit::TestCase
4
+ context "an authentication statement" do
5
+ setup do
6
+ @statement = AuthenticationStatement.new(AuthenticationContext.new())
7
+ end
8
+ should "always have a UTC time for authn_instant" do
9
+ assert_not_nil @statement.authn_instant
10
+ assert @statement.authn_instant.utc?
11
+ end
12
+ should "be valid" do
13
+ assert_nothing_raised do
14
+ @statement.validate
15
+ end
16
+ end
17
+ should "be invalid if authn_instant is not UTC" do
18
+ @statement.authn_instant = Time.now
19
+ assert_raise ValidationError do
20
+ @statement.validate
21
+ end
22
+ end
23
+ context "when producing xml" do
24
+ should "always include authn_instant" do
25
+ assert_match(/<saml:AuthnStatement AuthnInstant="#{date_match}">/, @statement.to_xml)
26
+ end
27
+ should "always include authn_context" do
28
+ assert_match(/<saml:AuthnContext>/, @statement.to_xml)
29
+ end
30
+ should "optionally include a session index" do
31
+ @statement.session_index = '12345'
32
+ assert_match(/SessionIndex="\d+"/, @statement.to_xml)
33
+ end
34
+ should "optionally include a session not on or after date" do
35
+ @statement.session_not_on_or_after = (Time.now + 5.days).utc
36
+ assert_match(/SessionNotOnOrAfter="#{date_match}"/, @statement.to_xml)
37
+ end
38
+ end
39
+ end
40
+ context "an attribute statement" do
41
+ setup do
42
+ @statement = AttributeStatement.new
43
+ @statement.attributes << Attribute.new('email', 'someone@someplace.com')
44
+ end
45
+ should "be valid" do
46
+ assert_nothing_raised { @statement.validate }
47
+ end
48
+ should "not be valid if empty attributes" do
49
+ assert_raise ValidationError do
50
+ @statement.attributes.clear
51
+ @statement.validate
52
+ end
53
+ end
54
+ context "when producing xml" do
55
+ should "include at least on attribute" do
56
+ assert_match(/<saml:AttributeStatement><saml:Attribute Name="email"><saml:AttributeValue>someone@someplace.com<\/saml:AttributeValue><\/saml:Attribute><\/saml:AttributeStatement>/, @statement.to_xml)
57
+ end
58
+ end
59
+ end
60
+
61
+ context "an authorization decision statement" do
62
+ setup do
63
+ @statement = AuthorizationDecisionStatement.new
64
+ @statement.resource = 'file://some/resource'
65
+ @statement.decision = 'Permit'
66
+ @statement.actions << Action.new('Read')
67
+ end
68
+ should "be valid" do
69
+ assert_nothing_raised { @statement.validate }
70
+ end
71
+ should "not be valid if resource is nil" do
72
+ assert_raise ValidationError do
73
+ @statement.resource = nil
74
+ @statement.validate
75
+ end
76
+ end
77
+ should "not be valid if decision is nil" do
78
+ assert_raise ValidationError do
79
+ @statement.decision = nil
80
+ @statement.validate
81
+ end
82
+ end
83
+ should "not be valid if no actions are specified" do
84
+ assert_raise ValidationError do
85
+ @statement.actions.clear
86
+ @statement.validate
87
+ end
88
+ end
89
+ context "when producing xml" do
90
+ should "include the AuthzStatement tag" do
91
+ assert_match(%Q(<saml:AuthzStatement), @statement.to_xml)
92
+ end
93
+ should "include a Resource attribute" do
94
+ assert_match(%Q(Resource="file://some/resource"), @statement.to_xml)
95
+ end
96
+ should "include a Decision attribute" do
97
+ assert_match(%Q(Decision="Permit"), @statement.to_xml)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class SubjectLocalityTest < Test::Unit::TestCase
4
+ context "a subject locality" do
5
+ setup do
6
+ @subject_locality = SubjectLocality.new
7
+ end
8
+ context "when validating" do
9
+ should "validate the address" do
10
+ @subject_locality.address = 'x'
11
+ assert_raise ValidationError do
12
+ @subject_locality.validate
13
+ end
14
+ end
15
+ end
16
+ context "when producing xml" do
17
+ should "optionally include an address" do
18
+ @subject_locality.address = '1.2.3.4'
19
+ assert_equal '<saml:SubjectLocality Address="1.2.3.4"/>', @subject_locality.to_xml
20
+ end
21
+ should "optionally include a dns name" do
22
+ @subject_locality.dns_name = 'example.com'
23
+ assert_equal '<saml:SubjectLocality DNSName="example.com"/>', @subject_locality.to_xml
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class SubjectTest < Test::Unit::TestCase
4
+ context "a subject with an identifier" do
5
+ setup do
6
+ @identifier = Identifier::Name.new('example')
7
+ @subject = Subject.new(@identifier)
8
+ end
9
+ should "have an identifier" do
10
+ assert_equal @identifier, @subject.identifier
11
+ end
12
+ context "when producing xml" do
13
+ should "should include the identifier" do
14
+ assert_equal '<saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">example</saml:NameID></saml:Subject>', @subject.to_xml
15
+ end
16
+ end
17
+ end
18
+ context "a subject with subject confirmations" do
19
+ setup do
20
+ @subject = Subject.new
21
+ @subject.subject_confirmations << SubjectConfirmation.new(SubjectConfirmation.methods[:holder_of_key])
22
+ end
23
+
24
+ context "when producing xml" do
25
+ should "optionally include subject confirmations" do
26
+ assert_equal '<saml:Subject><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"/></saml:Subject>', @subject.to_xml
27
+ end
28
+ end
29
+ end
30
+
31
+ context "a subject with an identifier and subject confirmations" do
32
+ setup do
33
+ @identifier = Identifier::Name.new('example')
34
+ @subject = Subject.new(@identifier)
35
+ @subject.subject_confirmations << SubjectConfirmation.new(SubjectConfirmation.methods[:holder_of_key])
36
+ end
37
+
38
+ context "when producing xml" do
39
+ should "include the identifier followed by the subject confirmations" do
40
+ assert_equal '<saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">example</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"/></saml:Subject>', @subject.to_xml
41
+ end
42
+ end
43
+ end
44
+ end