maestrano 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.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +43 -0
  5. data/LICENSE +21 -0
  6. data/README.md +4 -0
  7. data/Rakefile +32 -0
  8. data/bin/maestrano-console +9 -0
  9. data/lib/maestrano.rb +114 -0
  10. data/lib/maestrano/account/bill.rb +14 -0
  11. data/lib/maestrano/api/error/authentication_error.rb +8 -0
  12. data/lib/maestrano/api/error/base_error.rb +24 -0
  13. data/lib/maestrano/api/error/connection_error.rb +8 -0
  14. data/lib/maestrano/api/error/invalid_request_error.rb +14 -0
  15. data/lib/maestrano/api/list_object.rb +37 -0
  16. data/lib/maestrano/api/object.rb +187 -0
  17. data/lib/maestrano/api/operation/base.rb +216 -0
  18. data/lib/maestrano/api/operation/create.rb +18 -0
  19. data/lib/maestrano/api/operation/delete.rb +13 -0
  20. data/lib/maestrano/api/operation/list.rb +18 -0
  21. data/lib/maestrano/api/operation/update.rb +59 -0
  22. data/lib/maestrano/api/resource.rb +39 -0
  23. data/lib/maestrano/api/util.rb +121 -0
  24. data/lib/maestrano/saml/attribute_value.rb +15 -0
  25. data/lib/maestrano/saml/metadata.rb +64 -0
  26. data/lib/maestrano/saml/request.rb +93 -0
  27. data/lib/maestrano/saml/response.rb +201 -0
  28. data/lib/maestrano/saml/schemas/saml20assertion_schema.xsd +283 -0
  29. data/lib/maestrano/saml/schemas/saml20protocol_schema.xsd +302 -0
  30. data/lib/maestrano/saml/schemas/xenc_schema.xsd +146 -0
  31. data/lib/maestrano/saml/schemas/xmldsig_schema.xsd +318 -0
  32. data/lib/maestrano/saml/settings.rb +37 -0
  33. data/lib/maestrano/saml/validation_error.rb +7 -0
  34. data/lib/maestrano/sso.rb +81 -0
  35. data/lib/maestrano/sso/base_group.rb +31 -0
  36. data/lib/maestrano/sso/base_user.rb +75 -0
  37. data/lib/maestrano/sso/group.rb +24 -0
  38. data/lib/maestrano/sso/session.rb +63 -0
  39. data/lib/maestrano/sso/user.rb +34 -0
  40. data/lib/maestrano/version.rb +3 -0
  41. data/lib/maestrano/xml_security/signed_document.rb +170 -0
  42. data/maestrano.gemspec +32 -0
  43. data/test/helpers/api_helpers.rb +82 -0
  44. data/test/helpers/saml_helpers.rb +62 -0
  45. data/test/maestrano/account/bill_test.rb +48 -0
  46. data/test/maestrano/api/list_object_test.rb +20 -0
  47. data/test/maestrano/api/object_test.rb +28 -0
  48. data/test/maestrano/api/resource_test.rb +343 -0
  49. data/test/maestrano/api/util_test.rb +31 -0
  50. data/test/maestrano/maestrano_test.rb +49 -0
  51. data/test/maestrano/saml/request_test.rb +168 -0
  52. data/test/maestrano/saml/response_test.rb +290 -0
  53. data/test/maestrano/saml/settings_test.rb +51 -0
  54. data/test/maestrano/sso/base_group_test.rb +54 -0
  55. data/test/maestrano/sso/base_user_test.rb +114 -0
  56. data/test/maestrano/sso/group_test.rb +47 -0
  57. data/test/maestrano/sso/session_test.rb +108 -0
  58. data/test/maestrano/sso/user_test.rb +65 -0
  59. data/test/maestrano/sso_test.rb +81 -0
  60. data/test/maestrano/xml_security/signed_document.rb +163 -0
  61. data/test/support/saml/certificates/certificate1 +12 -0
  62. data/test/support/saml/certificates/r1_certificate2_base64 +1 -0
  63. data/test/support/saml/responses/adfs_response_sha1.xml +46 -0
  64. data/test/support/saml/responses/adfs_response_sha256.xml +46 -0
  65. data/test/support/saml/responses/adfs_response_sha384.xml +46 -0
  66. data/test/support/saml/responses/adfs_response_sha512.xml +46 -0
  67. data/test/support/saml/responses/no_signature_ns.xml +48 -0
  68. data/test/support/saml/responses/open_saml_response.xml +56 -0
  69. data/test/support/saml/responses/r1_response6.xml.base64 +1 -0
  70. data/test/support/saml/responses/response1.xml.base64 +1 -0
  71. data/test/support/saml/responses/response2.xml.base64 +79 -0
  72. data/test/support/saml/responses/response3.xml.base64 +66 -0
  73. data/test/support/saml/responses/response4.xml.base64 +93 -0
  74. data/test/support/saml/responses/response5.xml.base64 +102 -0
  75. data/test/support/saml/responses/response_with_ampersands.xml +139 -0
  76. data/test/support/saml/responses/response_with_ampersands.xml.base64 +93 -0
  77. data/test/support/saml/responses/response_with_multiple_attribute_values.xml +57 -0
  78. data/test/support/saml/responses/simple_saml_php.xml +71 -0
  79. data/test/support/saml/responses/starfield_response.xml.base64 +1 -0
  80. data/test/support/saml/responses/wrapped_response_2.xml.base64 +150 -0
  81. data/test/test_helper.rb +46 -0
  82. metadata +305 -0
@@ -0,0 +1,15 @@
1
+ module Maestrano
2
+ module Saml
3
+
4
+ # Wrapper for AttributeValue with multiple values
5
+ # It is subclass of String to be backwards compatible
6
+ # Use AttributeValue#values to get all values as an array
7
+ class AttributeValue < String
8
+ attr_accessor :values
9
+ def initialize(str="", values=[])
10
+ @values = values
11
+ super(str)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,64 @@
1
+ require "rexml/document"
2
+ require "rexml/xpath"
3
+ require "uri"
4
+
5
+ # Class to return SP metadata based on the settings requested.
6
+ # Return this XML in a controller, then give that URL to the the
7
+ # IdP administrator. The IdP will poll the URL and your settings
8
+ # will be updated automatically
9
+ module Maestrano
10
+ module Saml
11
+ include REXML
12
+ class Metadata
13
+ def generate(settings)
14
+ meta_doc = REXML::Document.new
15
+ root = meta_doc.add_element "md:EntityDescriptor", {
16
+ "xmlns:md" => "urn:oasis:names:tc:SAML:2.0:metadata"
17
+ }
18
+ sp_sso = root.add_element "md:SPSSODescriptor", {
19
+ "protocolSupportEnumeration" => "urn:oasis:names:tc:SAML:2.0:protocol",
20
+ # Metadata request need not be signed (as we don't publish our cert)
21
+ "AuthnRequestsSigned" => false,
22
+ # However we would like assertions signed if idp_cert_fingerprint or idp_cert is set
23
+ "WantAssertionsSigned" => (!settings.idp_cert_fingerprint.nil? || !settings.idp_cert.nil?)
24
+ }
25
+ if settings.issuer != nil
26
+ root.attributes["entityID"] = settings.issuer
27
+ end
28
+ if settings.assertion_consumer_logout_service_url != nil
29
+ sp_sso.add_element "md:SingleLogoutService", {
30
+ # Add this as a setting to create different bindings?
31
+ "Binding" => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
32
+ "Location" => settings.assertion_consumer_logout_service_url,
33
+ "ResponseLocation" => settings.assertion_consumer_logout_service_url,
34
+ "isDefault" => true,
35
+ "index" => 0
36
+ }
37
+ end
38
+ if settings.name_identifier_format != nil
39
+ name_id = sp_sso.add_element "md:NameIDFormat"
40
+ name_id.text = settings.name_identifier_format
41
+ end
42
+ if settings.assertion_consumer_service_url != nil
43
+ sp_sso.add_element "md:AssertionConsumerService", {
44
+ # Add this as a setting to create different bindings?
45
+ "Binding" => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
46
+ "Location" => settings.assertion_consumer_service_url,
47
+ "isDefault" => true,
48
+ "index" => 0
49
+ }
50
+ end
51
+ # With OpenSSO, it might be required to also include
52
+ # <md:RoleDescriptor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:query="urn:oasis:names:tc:SAML:metadata:ext:query" xsi:type="query:AttributeQueryDescriptorType" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
53
+ # <md:XACMLAuthzDecisionQueryDescriptor WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
54
+
55
+ meta_doc << REXML::XMLDecl.new
56
+ ret = ""
57
+ # pretty print the XML so IdP administrators can easily see what the SP supports
58
+ meta_doc.write(ret, 1)
59
+
60
+ ret
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,93 @@
1
+ require "base64"
2
+ require "uuid"
3
+ require "zlib"
4
+ require "cgi"
5
+ require "rexml/document"
6
+ require "rexml/xpath"
7
+
8
+ module Maestrano
9
+ module Saml
10
+ include REXML
11
+ class Request
12
+ attr_accessor :settings, :params, :session
13
+
14
+ def initialize(params = {}, session = {})
15
+ self.settings = Maestrano::SSO.saml_settings
16
+ self.params = params
17
+ self.session = session
18
+ end
19
+
20
+ def redirect_url
21
+ request_doc = create_authentication_xml_doc(settings)
22
+ request_doc.context[:attribute_quote] = :quote if self.settings.double_quote_xml_attribute_values
23
+
24
+ request = ""
25
+ request_doc.write(request)
26
+
27
+ request = Zlib::Deflate.deflate(request, 9)[2..-5] if self.settings.compress_request
28
+ base64_request = Base64.encode64(request)
29
+ encoded_request = CGI.escape(base64_request)
30
+ params_prefix = (self.settings.idp_sso_target_url =~ /\?/) ? '&' : '?'
31
+ request_params = "#{params_prefix}SAMLRequest=#{encoded_request}"
32
+
33
+ self.params.each_pair do |key, value|
34
+ request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
35
+ end
36
+
37
+ if (request_params !~ /group_id=/) && (group_id = (self.session[:mno_group_uid] || self.session['mno_group_uid']))
38
+ request_params << "&group_id=#{CGI.escape(group_id.to_s)}"
39
+ end
40
+
41
+ self.settings.idp_sso_target_url + request_params
42
+ end
43
+
44
+ def create_authentication_xml_doc(settings)
45
+ uuid = "_" + UUID.new.generate
46
+ time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
47
+ # Create AuthnRequest root element using REXML
48
+ request_doc = REXML::Document.new
49
+
50
+ root = request_doc.add_element "samlp:AuthnRequest", { "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol" }
51
+ root.attributes['ID'] = uuid
52
+ root.attributes['IssueInstant'] = time
53
+ root.attributes['Version'] = "2.0"
54
+ root.attributes['Destination'] = self.settings.idp_sso_target_url unless self.settings.idp_sso_target_url.nil?
55
+ root.attributes['IsPassive'] = self.settings.passive unless self.settings.passive.nil?
56
+ root.attributes['ProtocolBinding'] = self.settings.protocol_binding unless self.settings.protocol_binding.nil?
57
+
58
+ # Conditionally defined elements based on settings
59
+ if self.settings.assertion_consumer_service_url != nil
60
+ root.attributes["AssertionConsumerServiceURL"] = self.settings.assertion_consumer_service_url
61
+ end
62
+ if self.settings.issuer != nil
63
+ issuer = root.add_element "saml:Issuer", { "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
64
+ issuer.text = self.settings.issuer
65
+ end
66
+ if self.settings.name_identifier_format != nil
67
+ root.add_element "samlp:NameIDPolicy", {
68
+ "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
69
+ # Might want to make AllowCreate a setting?
70
+ "AllowCreate" => "true",
71
+ "Format" => self.settings.name_identifier_format
72
+ }
73
+ end
74
+
75
+ # BUG fix here -- if an authn_context is defined, add the tags with an "exact"
76
+ # match required for authentication to succeed. If this is not defined,
77
+ # the IdP will choose default rules for authentication. (Shibboleth IdP)
78
+ if self.settings.authn_context != nil
79
+ requested_context = root.add_element "samlp:RequestedAuthnContext", {
80
+ "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
81
+ "Comparison" => "exact",
82
+ }
83
+ class_ref = requested_context.add_element "saml:AuthnContextClassRef", {
84
+ "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion",
85
+ }
86
+ class_ref.text = self.settings.authn_context
87
+ end
88
+ request_doc
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,201 @@
1
+ require "time"
2
+ require "nokogiri"
3
+
4
+ # Only supports SAML 2.0
5
+ module Maestrano
6
+ module Saml
7
+
8
+ class Response
9
+ ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
10
+ PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
11
+ DSIG = "http://www.w3.org/2000/09/xmldsig#"
12
+
13
+ # TODO: This should probably be ctor initialized too... WDYT?
14
+ attr_accessor :settings
15
+
16
+ attr_reader :options
17
+ attr_reader :response
18
+ attr_reader :document
19
+
20
+ def initialize(response, options = {})
21
+ raise ArgumentError.new("Response cannot be nil") if response.nil?
22
+ @options = options
23
+ @response = (response =~ /^</) ? response : Base64.decode64(response)
24
+ @document = Maestrano::XMLSecurity::SignedDocument.new(@response)
25
+ @settings = Maestrano::SSO.saml_settings
26
+ end
27
+
28
+ def is_valid?
29
+ validate
30
+ end
31
+
32
+ def validate!
33
+ validate(false)
34
+ end
35
+
36
+ # The value of the user identifier as designated by the initialization request response
37
+ def name_id
38
+ @name_id ||= begin
39
+ node = xpath_first_from_signed_assertion('/a:Subject/a:NameID')
40
+ node.nil? ? nil : node.text
41
+ end
42
+ end
43
+
44
+ def sessionindex
45
+ @sessionindex ||= begin
46
+ node = xpath_first_from_signed_assertion('/a:AuthnStatement')
47
+ node.nil? ? nil : node.attributes['SessionIndex']
48
+ end
49
+ end
50
+
51
+ # A hash of all the attributes with the response.
52
+ # Multiple values will be returned in the AttributeValue#values array
53
+ # in reverse order, when compared to XML
54
+ def attributes
55
+ @attr_statements ||= begin
56
+ result = {}
57
+
58
+ stmt_element = xpath_first_from_signed_assertion('/a:AttributeStatement')
59
+ return {} if stmt_element.nil?
60
+
61
+ stmt_element.elements.each do |attr_element|
62
+ name = attr_element.attributes["Name"]
63
+ values = attr_element.elements.collect(&:text)
64
+
65
+ # Set up a string-like wrapper for the values array
66
+ attr_value = AttributeValue.new(values.first, values.reverse)
67
+ # Merge values if the Attribute has already been seen
68
+ if result[name]
69
+ attr_value.values += result[name].values
70
+ end
71
+
72
+ result[name] = attr_value
73
+ end
74
+
75
+ result.keys.each do |key|
76
+ result[key.intern] = result[key]
77
+ end
78
+
79
+ result
80
+ end
81
+ end
82
+
83
+ # When this user session should expire at latest
84
+ def session_expires_at
85
+ @expires_at ||= begin
86
+ node = xpath_first_from_signed_assertion('/a:AuthnStatement')
87
+ parse_time(node, "SessionNotOnOrAfter")
88
+ end
89
+ end
90
+
91
+ # Checks the status of the response for a "Success" code
92
+ def success?
93
+ @status_code ||= begin
94
+ node = REXML::XPath.first(document, "/p:Response/p:Status/p:StatusCode", { "p" => PROTOCOL, "a" => ASSERTION })
95
+ node.attributes["Value"] == "urn:oasis:names:tc:SAML:2.0:status:Success"
96
+ end
97
+ end
98
+
99
+ # Conditions (if any) for the assertion to run
100
+ def conditions
101
+ @conditions ||= xpath_first_from_signed_assertion('/a:Conditions')
102
+ end
103
+
104
+ def not_before
105
+ @not_before ||= parse_time(conditions, "NotBefore")
106
+ end
107
+
108
+ def not_on_or_after
109
+ @not_on_or_after ||= parse_time(conditions, "NotOnOrAfter")
110
+ end
111
+
112
+ def issuer
113
+ @issuer ||= begin
114
+ node = REXML::XPath.first(document, "/p:Response/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
115
+ node ||= xpath_first_from_signed_assertion('/a:Issuer')
116
+ node.nil? ? nil : node.text
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def validation_error(message)
123
+ raise ValidationError.new(message)
124
+ end
125
+
126
+ def validate(soft = true)
127
+ validate_structure(soft) &&
128
+ validate_response_state(soft) &&
129
+ validate_conditions(soft) &&
130
+ document.validate_document(get_fingerprint, soft) &&
131
+ success?
132
+ end
133
+
134
+ def validate_structure(soft = true)
135
+ Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), 'schemas'))) do
136
+ @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
137
+ @xml = Nokogiri::XML(self.document.to_s)
138
+ end
139
+ if soft
140
+ @schema.validate(@xml).map{ return false }
141
+ else
142
+ @schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
143
+ end
144
+ end
145
+
146
+ def validate_response_state(soft = true)
147
+ if response.empty?
148
+ return soft ? false : validation_error("Blank response")
149
+ end
150
+
151
+ if settings.nil?
152
+ return soft ? false : validation_error("No settings on response")
153
+ end
154
+
155
+ if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil?
156
+ return soft ? false : validation_error("No fingerprint or certificate on settings")
157
+ end
158
+
159
+ true
160
+ end
161
+
162
+ def xpath_first_from_signed_assertion(subelt=nil)
163
+ node = REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id}']#{subelt}", { "p" => PROTOCOL, "a" => ASSERTION })
164
+ node ||= REXML::XPath.first(document, "/p:Response[@ID='#{document.signed_element_id}']/a:Assertion#{subelt}", { "p" => PROTOCOL, "a" => ASSERTION })
165
+ node
166
+ end
167
+
168
+ def get_fingerprint
169
+ if settings.idp_cert
170
+ cert = OpenSSL::X509::Certificate.new(settings.idp_cert)
171
+ Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(":")
172
+ else
173
+ settings.idp_cert_fingerprint
174
+ end
175
+ end
176
+
177
+ def validate_conditions(soft = true)
178
+ return true if conditions.nil?
179
+ return true if options[:skip_conditions]
180
+
181
+ now = Time.now.utc
182
+
183
+ if not_before && (now + (options[:allowed_clock_drift] || 0)) < not_before
184
+ return soft ? false : validation_error("Current time is earlier than NotBefore condition")
185
+ end
186
+
187
+ if not_on_or_after && now >= not_on_or_after
188
+ return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
189
+ end
190
+
191
+ true
192
+ end
193
+
194
+ def parse_time(node, attribute)
195
+ if node && node.attributes[attribute]
196
+ Time.parse(node.attributes[attribute])
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,283 @@
1
+ <?xml version="1.0" encoding="US-ASCII"?>
2
+ <schema
3
+ targetNamespace="urn:oasis:names:tc:SAML:2.0:assertion"
4
+ xmlns="http://www.w3.org/2001/XMLSchema"
5
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
6
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
7
+ xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
8
+ elementFormDefault="unqualified"
9
+ attributeFormDefault="unqualified"
10
+ blockDefault="substitution"
11
+ version="2.0">
12
+ <import namespace="http://www.w3.org/2000/09/xmldsig#"
13
+ schemaLocation="xmldsig_schema.xsd"/>
14
+ <import namespace="http://www.w3.org/2001/04/xmlenc#"
15
+ schemaLocation="xenc_schema.xsd"/>
16
+ <annotation>
17
+ <documentation>
18
+ Document identifier: saml-schema-assertion-2.0
19
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
20
+ Revision history:
21
+ V1.0 (November, 2002):
22
+ Initial Standard Schema.
23
+ V1.1 (September, 2003):
24
+ Updates within the same V1.0 namespace.
25
+ V2.0 (March, 2005):
26
+ New assertion schema for SAML V2.0 namespace.
27
+ </documentation>
28
+ </annotation>
29
+ <attributeGroup name="IDNameQualifiers">
30
+ <attribute name="NameQualifier" type="string" use="optional"/>
31
+ <attribute name="SPNameQualifier" type="string" use="optional"/>
32
+ </attributeGroup>
33
+ <element name="BaseID" type="saml:BaseIDAbstractType"/>
34
+ <complexType name="BaseIDAbstractType" abstract="true">
35
+ <attributeGroup ref="saml:IDNameQualifiers"/>
36
+ </complexType>
37
+ <element name="NameID" type="saml:NameIDType"/>
38
+ <complexType name="NameIDType">
39
+ <simpleContent>
40
+ <extension base="string">
41
+ <attributeGroup ref="saml:IDNameQualifiers"/>
42
+ <attribute name="Format" type="anyURI" use="optional"/>
43
+ <attribute name="SPProvidedID" type="string" use="optional"/>
44
+ </extension>
45
+ </simpleContent>
46
+ </complexType>
47
+ <complexType name="EncryptedElementType">
48
+ <sequence>
49
+ <element ref="xenc:EncryptedData"/>
50
+ <element ref="xenc:EncryptedKey" minOccurs="0" maxOccurs="unbounded"/>
51
+ </sequence>
52
+ </complexType>
53
+ <element name="EncryptedID" type="saml:EncryptedElementType"/>
54
+ <element name="Issuer" type="saml:NameIDType"/>
55
+ <element name="AssertionIDRef" type="NCName"/>
56
+ <element name="AssertionURIRef" type="anyURI"/>
57
+ <element name="Assertion" type="saml:AssertionType"/>
58
+ <complexType name="AssertionType">
59
+ <sequence>
60
+ <element ref="saml:Issuer"/>
61
+ <element ref="ds:Signature" minOccurs="0"/>
62
+ <element ref="saml:Subject" minOccurs="0"/>
63
+ <element ref="saml:Conditions" minOccurs="0"/>
64
+ <element ref="saml:Advice" minOccurs="0"/>
65
+ <choice minOccurs="0" maxOccurs="unbounded">
66
+ <element ref="saml:Statement"/>
67
+ <element ref="saml:AuthnStatement"/>
68
+ <element ref="saml:AuthzDecisionStatement"/>
69
+ <element ref="saml:AttributeStatement"/>
70
+ </choice>
71
+ </sequence>
72
+ <attribute name="Version" type="string" use="required"/>
73
+ <attribute name="ID" type="ID" use="required"/>
74
+ <attribute name="IssueInstant" type="dateTime" use="required"/>
75
+ </complexType>
76
+ <element name="Subject" type="saml:SubjectType"/>
77
+ <complexType name="SubjectType">
78
+ <choice>
79
+ <sequence>
80
+ <choice>
81
+ <element ref="saml:BaseID"/>
82
+ <element ref="saml:NameID"/>
83
+ <element ref="saml:EncryptedID"/>
84
+ </choice>
85
+ <element ref="saml:SubjectConfirmation" minOccurs="0" maxOccurs="unbounded"/>
86
+ </sequence>
87
+ <element ref="saml:SubjectConfirmation" maxOccurs="unbounded"/>
88
+ </choice>
89
+ </complexType>
90
+ <element name="SubjectConfirmation" type="saml:SubjectConfirmationType"/>
91
+ <complexType name="SubjectConfirmationType">
92
+ <sequence>
93
+ <choice minOccurs="0">
94
+ <element ref="saml:BaseID"/>
95
+ <element ref="saml:NameID"/>
96
+ <element ref="saml:EncryptedID"/>
97
+ </choice>
98
+ <element ref="saml:SubjectConfirmationData" minOccurs="0"/>
99
+ </sequence>
100
+ <attribute name="Method" type="anyURI" use="required"/>
101
+ </complexType>
102
+ <element name="SubjectConfirmationData" type="saml:SubjectConfirmationDataType"/>
103
+ <complexType name="SubjectConfirmationDataType" mixed="true">
104
+ <complexContent>
105
+ <restriction base="anyType">
106
+ <sequence>
107
+ <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
108
+ </sequence>
109
+ <attribute name="NotBefore" type="dateTime" use="optional"/>
110
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
111
+ <attribute name="Recipient" type="anyURI" use="optional"/>
112
+ <attribute name="InResponseTo" type="NCName" use="optional"/>
113
+ <attribute name="Address" type="string" use="optional"/>
114
+ <anyAttribute namespace="##other" processContents="lax"/>
115
+ </restriction>
116
+ </complexContent>
117
+ </complexType>
118
+ <complexType name="KeyInfoConfirmationDataType" mixed="false">
119
+ <complexContent>
120
+ <restriction base="saml:SubjectConfirmationDataType">
121
+ <sequence>
122
+ <element ref="ds:KeyInfo" maxOccurs="unbounded"/>
123
+ </sequence>
124
+ </restriction>
125
+ </complexContent>
126
+ </complexType>
127
+ <element name="Conditions" type="saml:ConditionsType"/>
128
+ <complexType name="ConditionsType">
129
+ <choice minOccurs="0" maxOccurs="unbounded">
130
+ <element ref="saml:Condition"/>
131
+ <element ref="saml:AudienceRestriction"/>
132
+ <element ref="saml:OneTimeUse"/>
133
+ <element ref="saml:ProxyRestriction"/>
134
+ </choice>
135
+ <attribute name="NotBefore" type="dateTime" use="optional"/>
136
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
137
+ </complexType>
138
+ <element name="Condition" type="saml:ConditionAbstractType"/>
139
+ <complexType name="ConditionAbstractType" abstract="true"/>
140
+ <element name="AudienceRestriction" type="saml:AudienceRestrictionType"/>
141
+ <complexType name="AudienceRestrictionType">
142
+ <complexContent>
143
+ <extension base="saml:ConditionAbstractType">
144
+ <sequence>
145
+ <element ref="saml:Audience" maxOccurs="unbounded"/>
146
+ </sequence>
147
+ </extension>
148
+ </complexContent>
149
+ </complexType>
150
+ <element name="Audience" type="anyURI"/>
151
+ <element name="OneTimeUse" type="saml:OneTimeUseType" />
152
+ <complexType name="OneTimeUseType">
153
+ <complexContent>
154
+ <extension base="saml:ConditionAbstractType"/>
155
+ </complexContent>
156
+ </complexType>
157
+ <element name="ProxyRestriction" type="saml:ProxyRestrictionType"/>
158
+ <complexType name="ProxyRestrictionType">
159
+ <complexContent>
160
+ <extension base="saml:ConditionAbstractType">
161
+ <sequence>
162
+ <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
163
+ </sequence>
164
+ <attribute name="Count" type="nonNegativeInteger" use="optional"/>
165
+ </extension>
166
+ </complexContent>
167
+ </complexType>
168
+ <element name="Advice" type="saml:AdviceType"/>
169
+ <complexType name="AdviceType">
170
+ <choice minOccurs="0" maxOccurs="unbounded">
171
+ <element ref="saml:AssertionIDRef"/>
172
+ <element ref="saml:AssertionURIRef"/>
173
+ <element ref="saml:Assertion"/>
174
+ <element ref="saml:EncryptedAssertion"/>
175
+ <any namespace="##other" processContents="lax"/>
176
+ </choice>
177
+ </complexType>
178
+ <element name="EncryptedAssertion" type="saml:EncryptedElementType"/>
179
+ <element name="Statement" type="saml:StatementAbstractType"/>
180
+ <complexType name="StatementAbstractType" abstract="true"/>
181
+ <element name="AuthnStatement" type="saml:AuthnStatementType"/>
182
+ <complexType name="AuthnStatementType">
183
+ <complexContent>
184
+ <extension base="saml:StatementAbstractType">
185
+ <sequence>
186
+ <element ref="saml:SubjectLocality" minOccurs="0"/>
187
+ <element ref="saml:AuthnContext"/>
188
+ </sequence>
189
+ <attribute name="AuthnInstant" type="dateTime" use="required"/>
190
+ <attribute name="SessionIndex" type="string" use="optional"/>
191
+ <attribute name="SessionNotOnOrAfter" type="dateTime" use="optional"/>
192
+ </extension>
193
+ </complexContent>
194
+ </complexType>
195
+ <element name="SubjectLocality" type="saml:SubjectLocalityType"/>
196
+ <complexType name="SubjectLocalityType">
197
+ <attribute name="Address" type="string" use="optional"/>
198
+ <attribute name="DNSName" type="string" use="optional"/>
199
+ </complexType>
200
+ <element name="AuthnContext" type="saml:AuthnContextType"/>
201
+ <complexType name="AuthnContextType">
202
+ <sequence>
203
+ <choice>
204
+ <sequence>
205
+ <element ref="saml:AuthnContextClassRef"/>
206
+ <choice minOccurs="0">
207
+ <element ref="saml:AuthnContextDecl"/>
208
+ <element ref="saml:AuthnContextDeclRef"/>
209
+ </choice>
210
+ </sequence>
211
+ <choice>
212
+ <element ref="saml:AuthnContextDecl"/>
213
+ <element ref="saml:AuthnContextDeclRef"/>
214
+ </choice>
215
+ </choice>
216
+ <element ref="saml:AuthenticatingAuthority" minOccurs="0" maxOccurs="unbounded"/>
217
+ </sequence>
218
+ </complexType>
219
+ <element name="AuthnContextClassRef" type="anyURI"/>
220
+ <element name="AuthnContextDeclRef" type="anyURI"/>
221
+ <element name="AuthnContextDecl" type="anyType"/>
222
+ <element name="AuthenticatingAuthority" type="anyURI"/>
223
+ <element name="AuthzDecisionStatement" type="saml:AuthzDecisionStatementType"/>
224
+ <complexType name="AuthzDecisionStatementType">
225
+ <complexContent>
226
+ <extension base="saml:StatementAbstractType">
227
+ <sequence>
228
+ <element ref="saml:Action" maxOccurs="unbounded"/>
229
+ <element ref="saml:Evidence" minOccurs="0"/>
230
+ </sequence>
231
+ <attribute name="Resource" type="anyURI" use="required"/>
232
+ <attribute name="Decision" type="saml:DecisionType" use="required"/>
233
+ </extension>
234
+ </complexContent>
235
+ </complexType>
236
+ <simpleType name="DecisionType">
237
+ <restriction base="string">
238
+ <enumeration value="Permit"/>
239
+ <enumeration value="Deny"/>
240
+ <enumeration value="Indeterminate"/>
241
+ </restriction>
242
+ </simpleType>
243
+ <element name="Action" type="saml:ActionType"/>
244
+ <complexType name="ActionType">
245
+ <simpleContent>
246
+ <extension base="string">
247
+ <attribute name="Namespace" type="anyURI" use="required"/>
248
+ </extension>
249
+ </simpleContent>
250
+ </complexType>
251
+ <element name="Evidence" type="saml:EvidenceType"/>
252
+ <complexType name="EvidenceType">
253
+ <choice maxOccurs="unbounded">
254
+ <element ref="saml:AssertionIDRef"/>
255
+ <element ref="saml:AssertionURIRef"/>
256
+ <element ref="saml:Assertion"/>
257
+ <element ref="saml:EncryptedAssertion"/>
258
+ </choice>
259
+ </complexType>
260
+ <element name="AttributeStatement" type="saml:AttributeStatementType"/>
261
+ <complexType name="AttributeStatementType">
262
+ <complexContent>
263
+ <extension base="saml:StatementAbstractType">
264
+ <choice maxOccurs="unbounded">
265
+ <element ref="saml:Attribute"/>
266
+ <element ref="saml:EncryptedAttribute"/>
267
+ </choice>
268
+ </extension>
269
+ </complexContent>
270
+ </complexType>
271
+ <element name="Attribute" type="saml:AttributeType"/>
272
+ <complexType name="AttributeType">
273
+ <sequence>
274
+ <element ref="saml:AttributeValue" minOccurs="0" maxOccurs="unbounded"/>
275
+ </sequence>
276
+ <attribute name="Name" type="string" use="required"/>
277
+ <attribute name="NameFormat" type="anyURI" use="optional"/>
278
+ <attribute name="FriendlyName" type="string" use="optional"/>
279
+ <anyAttribute namespace="##other" processContents="lax"/>
280
+ </complexType>
281
+ <element name="AttributeValue" type="anyType" nillable="true"/>
282
+ <element name="EncryptedAttribute" type="saml:EncryptedElementType"/>
283
+ </schema>