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.
- data/LICENSE +0 -0
- data/README +13 -0
- data/Rakefile +136 -0
- data/lib/rsaml.rb +57 -0
- data/lib/rsaml/action.rb +57 -0
- data/lib/rsaml/action_namespace.rb +63 -0
- data/lib/rsaml/advice.rb +34 -0
- data/lib/rsaml/assertion.rb +192 -0
- data/lib/rsaml/attribute.rb +76 -0
- data/lib/rsaml/audience.rb +19 -0
- data/lib/rsaml/authentication_context.rb +34 -0
- data/lib/rsaml/authn_context/README +1 -0
- data/lib/rsaml/authn_context/authentication_context_declaration.rb +42 -0
- data/lib/rsaml/authn_context/identification.rb +10 -0
- data/lib/rsaml/authn_context/physical_verification.rb +24 -0
- data/lib/rsaml/condition.rb +13 -0
- data/lib/rsaml/conditions.rb +107 -0
- data/lib/rsaml/encrypted.rb +12 -0
- data/lib/rsaml/errors.rb +16 -0
- data/lib/rsaml/evidence.rb +21 -0
- data/lib/rsaml/ext/string.rb +5 -0
- data/lib/rsaml/identifier.rb +9 -0
- data/lib/rsaml/identifier/base.rb +23 -0
- data/lib/rsaml/identifier/issuer.rb +28 -0
- data/lib/rsaml/identifier/name.rb +55 -0
- data/lib/rsaml/parser.rb +23 -0
- data/lib/rsaml/protocol.rb +21 -0
- data/lib/rsaml/protocol/artifact_resolve.rb +14 -0
- data/lib/rsaml/protocol/assertion_id_request.rb +18 -0
- data/lib/rsaml/protocol/authn_request.rb +91 -0
- data/lib/rsaml/protocol/idp_entry.rb +18 -0
- data/lib/rsaml/protocol/idp_list.rb +28 -0
- data/lib/rsaml/protocol/message.rb +65 -0
- data/lib/rsaml/protocol/name_id_policy.rb +31 -0
- data/lib/rsaml/protocol/query.rb +12 -0
- data/lib/rsaml/protocol/query/attribute_query.rb +56 -0
- data/lib/rsaml/protocol/query/authn_query.rb +30 -0
- data/lib/rsaml/protocol/query/authz_decision_query.rb +40 -0
- data/lib/rsaml/protocol/query/subject_query.rb +22 -0
- data/lib/rsaml/protocol/request.rb +27 -0
- data/lib/rsaml/protocol/requested_authn_context.rb +34 -0
- data/lib/rsaml/protocol/response.rb +56 -0
- data/lib/rsaml/protocol/scoping.rb +33 -0
- data/lib/rsaml/protocol/status.rb +38 -0
- data/lib/rsaml/protocol/status_code.rb +84 -0
- data/lib/rsaml/proxy_restriction.rb +30 -0
- data/lib/rsaml/statement.rb +10 -0
- data/lib/rsaml/statement/attribute_statement.rb +27 -0
- data/lib/rsaml/statement/authentication_statement.rb +57 -0
- data/lib/rsaml/statement/authorization_decision_statement.rb +53 -0
- data/lib/rsaml/statement/base.rb +9 -0
- data/lib/rsaml/subject.rb +37 -0
- data/lib/rsaml/subject_confirmation.rb +35 -0
- data/lib/rsaml/subject_confirmation_data.rb +55 -0
- data/lib/rsaml/subject_locality.rb +27 -0
- data/lib/rsaml/validatable.rb +21 -0
- data/lib/rsaml/version.rb +9 -0
- data/lib/xml_enc.rb +3 -0
- data/lib/xml_sig.rb +11 -0
- data/lib/xml_sig/canonicalization_method.rb +43 -0
- data/lib/xml_sig/key_info.rb +55 -0
- data/lib/xml_sig/reference.rb +57 -0
- data/lib/xml_sig/signature.rb +29 -0
- data/lib/xml_sig/signature_method.rb +20 -0
- data/lib/xml_sig/signed_info.rb +27 -0
- data/lib/xml_sig/transform.rb +37 -0
- data/test/action_namespace_test.rb +93 -0
- data/test/action_test.rb +51 -0
- data/test/advice_test.rb +25 -0
- data/test/assertion_test.rb +192 -0
- data/test/attribute_test.rb +60 -0
- data/test/authentication_context_test.rb +26 -0
- data/test/conditions_test.rb +84 -0
- data/test/evidence_test.rb +33 -0
- data/test/identifier_test.rb +22 -0
- data/test/issuer_test.rb +33 -0
- data/test/name_test.rb +33 -0
- data/test/parser_test.rb +32 -0
- data/test/protocol/assertion_id_request_test.rb +19 -0
- data/test/protocol/attribute_query_test.rb +30 -0
- data/test/protocol/authn_query_test.rb +20 -0
- data/test/protocol/authn_request_test.rb +56 -0
- data/test/protocol/authz_decision_query_test.rb +31 -0
- data/test/protocol/idp_list_test.rb +15 -0
- data/test/protocol/request_test.rb +66 -0
- data/test/protocol/response_test.rb +68 -0
- data/test/protocol/scoping_test.rb +20 -0
- data/test/protocol/status_code_test.rb +34 -0
- data/test/protocol/status_test.rb +16 -0
- data/test/proxy_restriction_test.rb +20 -0
- data/test/rsaml_test.rb +12 -0
- data/test/statement_test.rb +101 -0
- data/test/subject_locality_test.rb +27 -0
- data/test/subject_test.rb +44 -0
- data/test/test_helper.rb +16 -0
- data/test/xml_sig/canonicalization_test.rb +19 -0
- metadata +187 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
# An XML signature.
|
3
|
+
class Signature
|
4
|
+
attr_accessor :id
|
5
|
+
attr_accessor :signed_info
|
6
|
+
attr_accessor :signature_value
|
7
|
+
attr_accessor :key_info
|
8
|
+
|
9
|
+
def objects
|
10
|
+
@objects ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert
|
14
|
+
# raise AssertionError, "An assertion signature must be valid"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Construct an XML fragment representing the signature
|
18
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
19
|
+
attributes = {}
|
20
|
+
attributes['Id'] = id unless id.nil?
|
21
|
+
attributes['xmlns:ds'] = "http://www.w3.org/2000/09/xmldsig#"
|
22
|
+
xml.tag!('ds:Signature', attributes) {
|
23
|
+
xml << signed_info.to_xml if signed_info
|
24
|
+
xml.tag!('ds:SignatureValue')
|
25
|
+
xml.tag!('ds:KeyInfo') if key_info
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
# SignatureMethod is a required element that specifies the algorithm used for
|
3
|
+
# signature generation and validation. This algorithm identifies all cryptographic
|
4
|
+
# functions involved in the signature operation (e.g. hashing, public key
|
5
|
+
# algorithms, MACs, padding, etc.).
|
6
|
+
class SignatureMethod
|
7
|
+
attr_accessor :algorithm
|
8
|
+
|
9
|
+
def validate
|
10
|
+
raise ValidationError, "Algorithm is required" if algorithm.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
14
|
+
attributes = {'Algorightm' => algorithm}
|
15
|
+
xml.tag!('ds:SignatureMethod', attributes) {
|
16
|
+
xml.tag!('ds:HMACOutputLength', hmac_output_length) unless hmac_output_length.nil?
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
class SignedInfo
|
3
|
+
attr_accessor :id
|
4
|
+
attr_accessor :canonicalization_method
|
5
|
+
attr_accessor :signature_method
|
6
|
+
|
7
|
+
def references
|
8
|
+
@references ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate
|
12
|
+
raise ValidationError, "Canonicalization method is required" if canonicalization_method.nil?
|
13
|
+
raise ValidationError, "Signature method is required" if signature_method.nil?
|
14
|
+
raise ValidationError, "At least one reference is required" if references.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
18
|
+
attributes = {}
|
19
|
+
attributes['Id'] = id unless id.nil?
|
20
|
+
xml.tag!('ds:SignedInfo', attributes) {
|
21
|
+
xml << canonicalization_method.to_xml unless canonicalization_method.nil?
|
22
|
+
xml << signature_method.to_xml unless signature_method.nil?
|
23
|
+
references.each { |reference| xml << reference.to_xml }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module XmlSig #:nodoc:
|
2
|
+
class Transform
|
3
|
+
attr_accessor :algorithm
|
4
|
+
attr_accessor :xpath
|
5
|
+
|
6
|
+
def to_xml(xml=Builder::XmlMarkup.new)
|
7
|
+
attributes = {'Algorightm' => algorithm}
|
8
|
+
xml.tag!('ds:Transform', attributes) {
|
9
|
+
xml.tag!('ds:XPath', xpath) unless xpath.nil?
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class Base64Transform
|
14
|
+
IDENTIFIER = 'http://www.w3.org/2000/09/xmldsig#base64'
|
15
|
+
def process(content)
|
16
|
+
content # TODO: implement
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class XPathFiltering
|
20
|
+
IDENTIFIER = 'http://www.w3.org/TR/1999/REC-xpath-19991116'
|
21
|
+
def process(content)
|
22
|
+
content # TODO: implement
|
23
|
+
end
|
24
|
+
end
|
25
|
+
class EnvelopedSignatureTransform
|
26
|
+
IDENTIFIER = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
|
27
|
+
def process(content)
|
28
|
+
content # TODO: implement
|
29
|
+
end
|
30
|
+
end
|
31
|
+
class XSLTTransform
|
32
|
+
IDENTIFIER = 'http://www.w3.org/TR/1999/REC-xslt-19991116'
|
33
|
+
def process(content)
|
34
|
+
content # TODO: implement
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ActionNamespaceTest < Test::Unit::TestCase
|
4
|
+
context "the ActionNamespace class" do
|
5
|
+
should "define all of the namespaces in the SAML 2.0 specification" do
|
6
|
+
namespace_uris = ActionNamespace.namespaces.values.collect { |ns| ns.uri }
|
7
|
+
assert namespace_uris.include?('urn:oasis:names:tc:SAML:1.0:action:rwedc')
|
8
|
+
assert namespace_uris.include?('urn:oasis:names:tc:SAML:1.0:action:rwedc-negation')
|
9
|
+
assert namespace_uris.include?('urn:oasis:names:tc:SAML:1.0:action:ghpp')
|
10
|
+
assert namespace_uris.include?('urn:oasis:names:tc:SAML:1.0:action:unix')
|
11
|
+
end
|
12
|
+
should "return a namespace instance given a URI" do
|
13
|
+
assert_equal(ActionNamespace.namespaces[:rwedc],
|
14
|
+
ActionNamespace.namespace_for_uri('urn:oasis:names:tc:SAML:1.0:action:rwedc')
|
15
|
+
)
|
16
|
+
assert_equal(ActionNamespace.namespaces[:rwedc_negation],
|
17
|
+
ActionNamespace.namespace_for_uri('urn:oasis:names:tc:SAML:1.0:action:rwedc-negation')
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
context "the rwdec namespace" do
|
22
|
+
setup do
|
23
|
+
@action_namespace = ActionNamespace.namespaces[:rwedc]
|
24
|
+
@expected_actions = ['Read','Write','Execute','Delete','Control']
|
25
|
+
end
|
26
|
+
should "have the correct uri" do
|
27
|
+
assert_equal 'urn:oasis:names:tc:SAML:1.0:action:rwedc', @action_namespace.uri
|
28
|
+
end
|
29
|
+
should "return the uri when to_s is invoked" do
|
30
|
+
assert_equal @action_namespace.uri, @action_namespace.to_s
|
31
|
+
end
|
32
|
+
should "have the correct actions" do
|
33
|
+
assert_equal @expected_actions, @action_namespace.action_names
|
34
|
+
end
|
35
|
+
should "return true for a valid action" do
|
36
|
+
@expected_actions.each do |action|
|
37
|
+
assert @action_namespace.valid_action?(action)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
should "return false for an invalid action" do
|
41
|
+
assert_equal false, @action_namespace.valid_action?('invalid-action')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
context "the rwdec-negation namespace" do
|
45
|
+
setup do
|
46
|
+
@action_namespace = ActionNamespace.namespaces[:rwedc_negation]
|
47
|
+
@expected_actions = [
|
48
|
+
'Read','Write','Execute','Delete','Control',
|
49
|
+
'~Read','~Write','~Execute','~Delete','~Control'
|
50
|
+
]
|
51
|
+
end
|
52
|
+
should "have the correct uri" do
|
53
|
+
assert_equal 'urn:oasis:names:tc:SAML:1.0:action:rwedc-negation', @action_namespace.uri
|
54
|
+
end
|
55
|
+
should "have the correct actions" do
|
56
|
+
assert_equal @expected_actions, @action_namespace.action_names
|
57
|
+
end
|
58
|
+
should "return true for a valid action" do
|
59
|
+
@expected_actions.each do |action|
|
60
|
+
assert @action_namespace.valid_action?(action)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
should "return false for an invalid action" do
|
64
|
+
assert_equal false, @action_namespace.valid_action?('invalid-action')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
context "the ghpp namespace" do
|
68
|
+
setup do
|
69
|
+
@action_namespace = ActionNamespace.namespaces[:ghpp]
|
70
|
+
@expected_actions = ['GET','HEAD','PUT','POST']
|
71
|
+
end
|
72
|
+
should "have the correct uri" do
|
73
|
+
assert_equal 'urn:oasis:names:tc:SAML:1.0:action:ghpp', @action_namespace.uri
|
74
|
+
end
|
75
|
+
should "have the correct actions" do
|
76
|
+
assert_equal @expected_actions, @action_namespace.action_names
|
77
|
+
end
|
78
|
+
should "return false for an invalid action" do
|
79
|
+
assert_equal false, @action_namespace.valid_action?('invalid-action')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
context "the unix file permissions namespace" do
|
83
|
+
setup do
|
84
|
+
@action_namespace = ActionNamespace.namespaces[:unix]
|
85
|
+
end
|
86
|
+
should "have the correct uri" do
|
87
|
+
assert_equal 'urn:oasis:names:tc:SAML:1.0:action:unix', @action_namespace.uri
|
88
|
+
end
|
89
|
+
should_eventually "have the correct actions" do
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/test/action_test.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ActionTest < Test::Unit::TestCase
|
4
|
+
context "an action" do
|
5
|
+
setup do
|
6
|
+
@action = Action.new('Read')
|
7
|
+
end
|
8
|
+
should "have the rwedc_negation namespace by default" do
|
9
|
+
assert_equal Action.namespaces[:rwedc_negation], @action.namespace
|
10
|
+
end
|
11
|
+
should "be valid by default" do
|
12
|
+
assert @action.valid?
|
13
|
+
end
|
14
|
+
context "when producing xml" do
|
15
|
+
should "optionally have a namespace" do
|
16
|
+
assert_match(/<saml:Action Namespace="#{@action.namespace}"/, @action.to_xml)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
context "when consuming xml" do
|
20
|
+
should "return a valid Action instance" do
|
21
|
+
action = Action.from_xml('<saml:Action xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">Read</saml:Action>')
|
22
|
+
assert_not_nil(action)
|
23
|
+
assert_equal 'Read', action.value
|
24
|
+
assert_equal Action.namespaces[:rwedc_negation], action.namespace
|
25
|
+
assert action.valid?
|
26
|
+
end
|
27
|
+
context "with an action namespace attribute" do
|
28
|
+
should "return a valid Action instance with an action namespace" do
|
29
|
+
action = Action.from_xml(%Q(<saml:Action xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Namespace="#{Action.namespaces[:rwedc]}">Write</saml:Action>))
|
30
|
+
assert_not_nil(action)
|
31
|
+
assert_equal 'Write', action.value
|
32
|
+
assert_equal Action.namespaces[:rwedc], action.namespace
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
context "when validating" do
|
37
|
+
should "raise an error if no value is provided" do
|
38
|
+
assert_raise ValidationError do
|
39
|
+
@action.value = nil
|
40
|
+
@action.validate
|
41
|
+
end
|
42
|
+
end
|
43
|
+
should "raise an error if the value is not in the specified namespace" do
|
44
|
+
assert_raise ValidationError do
|
45
|
+
@action.value = 'PUT'
|
46
|
+
@action.validate
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/test/advice_test.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class AdviceTest < Test::Unit::TestCase
|
4
|
+
context "an advice" do
|
5
|
+
setup { @advice = Advice.new }
|
6
|
+
should "have 0 assertions by default" do
|
7
|
+
assert @advice.assertions.empty?
|
8
|
+
end
|
9
|
+
should "be valid if all assertions are valid" do
|
10
|
+
assert @advice.valid?
|
11
|
+
end
|
12
|
+
context "when producing xml" do
|
13
|
+
should "produce an empty advice tag when there are no assertions" do
|
14
|
+
assert_match(/<saml:Advice><\/saml:Advice>/, @advice.to_xml)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
context "when consuming xml" do
|
18
|
+
should "return a valid Advice instance" do
|
19
|
+
advice = Advice.from_xml('<saml:Advice xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"></saml:Advice>')
|
20
|
+
assert_not_nil(advice)
|
21
|
+
assert advice.valid?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class AssertionTest < Test::Unit::TestCase
|
4
|
+
context "an assertion" do
|
5
|
+
setup do
|
6
|
+
@issuer = Identifier::Issuer.new('example')
|
7
|
+
@assertion = Assertion.new(@issuer)
|
8
|
+
end
|
9
|
+
should "require version of 2.0" do
|
10
|
+
assert_equal "2.0", @assertion.version
|
11
|
+
end
|
12
|
+
should "require ID" do
|
13
|
+
assert_not_nil @assertion.id
|
14
|
+
end
|
15
|
+
should "require issue instant" do
|
16
|
+
assert_not_nil @assertion.issue_instant
|
17
|
+
end
|
18
|
+
should "require an issuer" do
|
19
|
+
assert_not_nil @assertion.issuer
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with only a subject" do
|
23
|
+
setup do
|
24
|
+
@assertion.subject = 'test'
|
25
|
+
end
|
26
|
+
should "be valid" do
|
27
|
+
assert_nothing_raised do
|
28
|
+
@assertion.validate
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
context "with an authentication statement" do
|
33
|
+
setup do
|
34
|
+
@assertion.statements << AuthenticationStatement.new(AuthenticationContext.new)
|
35
|
+
end
|
36
|
+
should "require a subject" do
|
37
|
+
assert_raise ValidationError do
|
38
|
+
@assertion.validate
|
39
|
+
end
|
40
|
+
assert !@assertion.valid?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
context "with an attribute statement" do
|
44
|
+
setup do
|
45
|
+
@assertion.statements << AttributeStatement.new
|
46
|
+
end
|
47
|
+
should "require a subject" do
|
48
|
+
assert_raise ValidationError do
|
49
|
+
@assertion.validate
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context "with a authorization decision statement" do
|
54
|
+
setup do
|
55
|
+
@assertion.statements << AuthorizationDecisionStatement.new
|
56
|
+
end
|
57
|
+
should "require a subject" do
|
58
|
+
assert_raise ValidationError do
|
59
|
+
@assertion.validate
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when producing xml" do
|
65
|
+
# TODO: implement tests for XML results
|
66
|
+
should "always include version, id and issue instant attributes and an issuer child element" do
|
67
|
+
xml = @assertion.to_xml
|
68
|
+
assert_match(/^<saml:Assertion/, xml)
|
69
|
+
assert_match(/Version="2.0"/, xml)
|
70
|
+
assert_match(/ID="#{uuid_match}"/, xml)
|
71
|
+
assert_match(/IssueInstant="#{date_match}"/, xml)
|
72
|
+
assert_match(/<saml:Issuer/, xml)
|
73
|
+
end
|
74
|
+
should "optionally include a signature" do
|
75
|
+
@assertion.signature = XmlSig::Signature.new
|
76
|
+
xml = @assertion.to_xml
|
77
|
+
assert_match(/<ds:Signature/, xml)
|
78
|
+
end
|
79
|
+
should "optionally include a subject" do
|
80
|
+
@assertion.subject = Subject.new(Identifier::Name.new('The Subject'))
|
81
|
+
xml = @assertion.to_xml
|
82
|
+
assert_match(%Q(<saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">The Subject</saml:NameID></saml:Subject>), xml)
|
83
|
+
end
|
84
|
+
should "optionally include conditions" do
|
85
|
+
@assertion.conditions << Condition.new
|
86
|
+
xml = @assertion.to_xml
|
87
|
+
assert_match(/<saml:Conditions>/, xml)
|
88
|
+
end
|
89
|
+
should "optionally include advice" do
|
90
|
+
uri = 'http://example.com/some_advice'
|
91
|
+
advice = Advice.new
|
92
|
+
advice.assertions << AssertionIDRef.new(UUID.new.generate)
|
93
|
+
advice.assertions << AssertionURIRef.new(uri) # a URI
|
94
|
+
@assertion.advice << advice
|
95
|
+
xml = @assertion.to_xml
|
96
|
+
assert_match(/<saml:Advice><saml:AssertionIDRef>#{uuid_match}<\/saml:AssertionIDRef>/, xml)
|
97
|
+
assert_match(/<saml:AssertionURIRef>#{uri}<\/saml:AssertionURIRef><\/saml:Advice>/, xml)
|
98
|
+
end
|
99
|
+
should "optionally include statements" do
|
100
|
+
@assertion.statements << AuthenticationStatement.new(AuthenticationContext.new)
|
101
|
+
xml = @assertion.to_xml
|
102
|
+
assert_match(/<saml:AuthnStatement AuthnInstant="#{date_match}"/, xml)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when consuming xml" do
|
107
|
+
should "return a valid Assertion instance" do
|
108
|
+
xml_fragment = %Q(
|
109
|
+
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
|
110
|
+
<saml:Issuer>Example</saml:Issuer>
|
111
|
+
<saml:Subject>Anthony</saml:Subject>
|
112
|
+
</saml:Assertion>
|
113
|
+
)
|
114
|
+
assertion = Assertion.from_xml(xml_fragment)
|
115
|
+
assert_not_nil assertion
|
116
|
+
assert_not_nil assertion.issuer
|
117
|
+
assert_equal 'Example', assertion.issuer.value
|
118
|
+
assert_nothing_raised do
|
119
|
+
assertion.validate
|
120
|
+
end
|
121
|
+
end
|
122
|
+
context "where there is no saml:Subject element" do
|
123
|
+
should "raise a validation error" do
|
124
|
+
xml_fragment = %Q(
|
125
|
+
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
|
126
|
+
<saml:Issuer>Example</saml:Issuer>
|
127
|
+
</saml:Assertion>
|
128
|
+
)
|
129
|
+
assertion = Assertion.from_xml(xml_fragment)
|
130
|
+
assert_raise ValidationError do
|
131
|
+
assertion.validate
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
context "an assertion URI ref" do
|
138
|
+
setup do
|
139
|
+
@assertion_uri_ref = AssertionURIRef.new('some_uri')
|
140
|
+
end
|
141
|
+
should "provide a uri accessor" do
|
142
|
+
assert_equal 'some_uri', @assertion_uri_ref.uri
|
143
|
+
end
|
144
|
+
context "when validating" do
|
145
|
+
should "raise an error if no uri is provided" do
|
146
|
+
assert_raise ValidationError do
|
147
|
+
@assertion_uri_ref.uri = nil
|
148
|
+
@assertion_uri_ref.validate
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
context "when producing xml" do
|
153
|
+
should "have the uri as the value" do
|
154
|
+
assert_match(/<saml:AssertionURIRef>some_uri<\/saml:AssertionURIRef>/, @assertion_uri_ref.to_xml)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
context "when consuming xml" do
|
158
|
+
should "return a valid AssertionURIRef instance" do
|
159
|
+
assertion_ref = AssertionURIRef.from_xml('<saml:AssertionURIRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">some_uri</saml:AssertionURIRef>')
|
160
|
+
assert_not_nil assertion_ref
|
161
|
+
assert_equal 'some_uri', assertion_ref.uri
|
162
|
+
assert assertion_ref.valid?
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
context "an assertion ID ref" do
|
167
|
+
setup do
|
168
|
+
@assertion_id_ref = AssertionIDRef.new('some_id')
|
169
|
+
end
|
170
|
+
context "when validating" do
|
171
|
+
should "raise an error if no id is provided" do
|
172
|
+
assert_raise ValidationError do
|
173
|
+
@assertion_id_ref.id = nil
|
174
|
+
@assertion_id_ref.validate
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
context "when producing xml" do
|
179
|
+
should "have an id as the value" do
|
180
|
+
assert_match(/<saml:AssertionIDRef>some_id<\/saml:AssertionIDRef>/, @assertion_id_ref.to_xml)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
context "when consuming xml" do
|
184
|
+
should "return a valid AssertionIDRef instance" do
|
185
|
+
assertion_ref = AssertionIDRef.from_xml('<saml:AssertionIDRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">some_id</saml:AssertionIDRef>')
|
186
|
+
assert_not_nil assertion_ref
|
187
|
+
assert_equal 'some_id', assertion_ref.id
|
188
|
+
assert assertion_ref.valid?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|