ruby-saml-bm 0.6.1

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 (43) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +51 -0
  3. data/LICENSE +19 -0
  4. data/README.md +126 -0
  5. data/Rakefile +41 -0
  6. data/lib/onelogin/ruby-saml-bm/authrequest.rb +79 -0
  7. data/lib/onelogin/ruby-saml-bm/logging.rb +26 -0
  8. data/lib/onelogin/ruby-saml-bm/logoutrequest.rb +80 -0
  9. data/lib/onelogin/ruby-saml-bm/metadata.rb +47 -0
  10. data/lib/onelogin/ruby-saml-bm/response.rb +180 -0
  11. data/lib/onelogin/ruby-saml-bm/settings.rb +18 -0
  12. data/lib/onelogin/ruby-saml-bm/validation_error.rb +7 -0
  13. data/lib/onelogin/ruby-saml-bm/version.rb +5 -0
  14. data/lib/ruby-saml.rb +8 -0
  15. data/lib/schemas/saml20assertion_schema.xsd +283 -0
  16. data/lib/schemas/saml20protocol_schema.xsd +302 -0
  17. data/lib/schemas/xenc_schema.xsd +146 -0
  18. data/lib/schemas/xmldsig_schema.xsd +318 -0
  19. data/lib/xml_security.rb +165 -0
  20. data/ruby-saml-bm.gemspec +29 -0
  21. data/test/certificates/certificate1 +12 -0
  22. data/test/logoutrequest_test.rb +98 -0
  23. data/test/request_test.rb +53 -0
  24. data/test/response_test.rb +219 -0
  25. data/test/responses/adfs_response_sha1.xml +46 -0
  26. data/test/responses/adfs_response_sha256.xml +46 -0
  27. data/test/responses/adfs_response_sha384.xml +46 -0
  28. data/test/responses/adfs_response_sha512.xml +46 -0
  29. data/test/responses/no_signature_ns.xml +48 -0
  30. data/test/responses/open_saml_response.xml +56 -0
  31. data/test/responses/response1.xml.base64 +1 -0
  32. data/test/responses/response2.xml.base64 +79 -0
  33. data/test/responses/response3.xml.base64 +66 -0
  34. data/test/responses/response4.xml.base64 +93 -0
  35. data/test/responses/response5.xml.base64 +102 -0
  36. data/test/responses/response_with_ampersands.xml +139 -0
  37. data/test/responses/response_with_ampersands.xml.base64 +93 -0
  38. data/test/responses/simple_saml_php.xml +71 -0
  39. data/test/responses/wrapped_response_2.xml.base64 +150 -0
  40. data/test/settings_test.rb +43 -0
  41. data/test/test_helper.rb +66 -0
  42. data/test/xml_security_test.rb +123 -0
  43. metadata +165 -0
@@ -0,0 +1,180 @@
1
+ require "xml_security"
2
+ require "time"
3
+ require "nokogiri"
4
+
5
+ # Only supports SAML 2.0
6
+ module Onelogin
7
+ module Saml
8
+
9
+ class Response
10
+ ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
11
+ PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
12
+ DSIG = "http://www.w3.org/2000/09/xmldsig#"
13
+
14
+ attr_accessor :options, :response, :document, :settings
15
+
16
+ def initialize(response, options = {})
17
+ raise ArgumentError.new("Response cannot be nil") if response.nil?
18
+ self.options = options
19
+ self.response = response
20
+
21
+ begin
22
+ self.document = XMLSecurity::SignedDocument.new(Base64.decode64(response))
23
+ rescue REXML::ParseException => e
24
+ if response =~ /</
25
+ self.document = XMLSecurity::SignedDocument.new(response)
26
+ else
27
+ raise e
28
+ end
29
+ end
30
+ end
31
+
32
+ def is_valid?
33
+ validate
34
+ end
35
+
36
+ def validate!
37
+ validate(false)
38
+ end
39
+
40
+ # The value of the user identifier as designated by the initialization request response
41
+ def name_id
42
+ @name_id ||= begin
43
+ node = REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id}']/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
44
+ node ||= REXML::XPath.first(document, "/p:Response[@ID='#{document.signed_element_id}']/a:Assertion/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
45
+ node.nil? ? nil : node.text
46
+ end
47
+ end
48
+
49
+ # A hash of alle the attributes with the response. Assuming there is only one value for each key
50
+ def attributes
51
+ @attr_statements ||= begin
52
+ result = {}
53
+
54
+ stmt_element = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AttributeStatement", { "p" => PROTOCOL, "a" => ASSERTION })
55
+ return {} if stmt_element.nil?
56
+
57
+ stmt_element.elements.each do |attr_element|
58
+ name = attr_element.attributes["Name"]
59
+ value = attr_element.elements.first.text
60
+
61
+ result[name] = value
62
+ end
63
+
64
+ result.keys.each do |key|
65
+ result[key.intern] = result[key]
66
+ end
67
+
68
+ result
69
+ end
70
+ end
71
+
72
+ # When this user session should expire at latest
73
+ def session_expires_at
74
+ @expires_at ||= begin
75
+ node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AuthnStatement", { "p" => PROTOCOL, "a" => ASSERTION })
76
+ parse_time(node, "SessionNotOnOrAfter")
77
+ end
78
+ end
79
+
80
+ # Checks the status of the response for a "Success" code
81
+ def success?
82
+ @status_code ||= begin
83
+ node = REXML::XPath.first(document, "/p:Response/p:Status/p:StatusCode", { "p" => PROTOCOL, "a" => ASSERTION })
84
+ node.attributes["Value"] == "urn:oasis:names:tc:SAML:2.0:status:Success"
85
+ end
86
+ end
87
+
88
+ # Conditions (if any) for the assertion to run
89
+ def conditions
90
+ @conditions ||= begin
91
+ REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id}']/a:Conditions", { "p" => PROTOCOL, "a" => ASSERTION })
92
+ end
93
+ end
94
+
95
+ def issuer
96
+ @issuer ||= begin
97
+ node = REXML::XPath.first(document, "/p:Response/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
98
+ node ||= REXML::XPath.first(document, "/p:Response/a:Assertion/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
99
+ node.nil? ? nil : node.text
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def validation_error(message)
106
+ raise ValidationError.new(message)
107
+ end
108
+
109
+ def validate(soft = true)
110
+ validate_structure(soft) &&
111
+ validate_response_state(soft) &&
112
+ validate_conditions(soft) &&
113
+ document.validate(get_fingerprint, soft) &&
114
+ success?
115
+ end
116
+
117
+ def validate_structure(soft = true)
118
+ Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
119
+ @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
120
+ @xml = Nokogiri::XML(self.document.to_s)
121
+ end
122
+ if soft
123
+ @schema.validate(@xml).map{ return false }
124
+ else
125
+ @schema.validate(@xml).map{ |error| raise(Exception.new("#{error.message}\n\n#{@xml.to_s}")) }
126
+ end
127
+ end
128
+
129
+ def validate_response_state(soft = true)
130
+ if response.empty?
131
+ return soft ? false : validation_error("Blank response")
132
+ end
133
+
134
+ if settings.nil?
135
+ return soft ? false : validation_error("No settings on response")
136
+ end
137
+
138
+ if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil?
139
+ return soft ? false : validation_error("No fingerprint or certificate on settings")
140
+ end
141
+
142
+ true
143
+ end
144
+
145
+ def get_fingerprint
146
+ if settings.idp_cert
147
+ cert = OpenSSL::X509::Certificate.new(settings.idp_cert)
148
+ Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(":")
149
+ else
150
+ settings.idp_cert_fingerprint
151
+ end
152
+ end
153
+
154
+ def validate_conditions(soft = true)
155
+ return true if conditions.nil?
156
+ return true if options[:skip_conditions]
157
+
158
+ if not_before = parse_time(conditions, "NotBefore")
159
+ if Time.now.utc < not_before
160
+ return soft ? false : validation_error("Current time is earlier than NotBefore condition")
161
+ end
162
+ end
163
+
164
+ if not_on_or_after = parse_time(conditions, "NotOnOrAfter")
165
+ if Time.now.utc >= not_on_or_after
166
+ return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
167
+ end
168
+ end
169
+
170
+ true
171
+ end
172
+
173
+ def parse_time(node, attribute)
174
+ if node && node.attributes[attribute]
175
+ Time.parse(node.attributes[attribute])
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,18 @@
1
+ module Onelogin
2
+ module Saml
3
+ class Settings
4
+ def initialize(config = {})
5
+ config.each do |k,v|
6
+ acc = "#{k.to_s}=".to_sym
7
+ self.send(acc, v) if self.respond_to? acc
8
+ end
9
+ end
10
+ attr_accessor :assertion_consumer_service_url, :issuer, :sp_name_qualifier
11
+ attr_accessor :idp_sso_target_url, :idp_cert_fingerprint, :idp_cert, :name_identifier_format
12
+ attr_accessor :authn_context
13
+ attr_accessor :idp_slo_target_url
14
+ attr_accessor :name_identifier_value
15
+ attr_accessor :sessionindex
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module Onelogin
2
+ module Saml
3
+ class ValidationError < Exception
4
+ end
5
+ end
6
+ end
7
+
@@ -0,0 +1,5 @@
1
+ module Onelogin
2
+ module Saml
3
+ VERSION = '0.6.1'
4
+ end
5
+ end
data/lib/ruby-saml.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'onelogin/ruby-saml-bm/logging'
2
+ require 'onelogin/ruby-saml-bm/authrequest'
3
+ require 'onelogin/ruby-saml-bm/logoutrequest'
4
+ require 'onelogin/ruby-saml-bm/response'
5
+ require 'onelogin/ruby-saml-bm/settings'
6
+ require 'onelogin/ruby-saml-bm/validation_error'
7
+ require 'onelogin/ruby-saml-bm/metadata'
8
+ require 'onelogin/ruby-saml-bm/version'
@@ -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>