rsaml 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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