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