ruby-saml 1.16.0 → 1.18.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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/workflows/test.yml +49 -3
- data/CHANGELOG.md +31 -8
- data/README.md +96 -69
- data/UPGRADING.md +9 -0
- data/lib/onelogin/ruby-saml/authrequest.rb +7 -8
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +6 -8
- data/lib/onelogin/ruby-saml/logoutrequest.rb +6 -6
- data/lib/onelogin/ruby-saml/logoutresponse.rb +2 -1
- data/lib/onelogin/ruby-saml/metadata.rb +21 -25
- data/lib/onelogin/ruby-saml/response.rb +116 -52
- data/lib/onelogin/ruby-saml/saml_message.rb +21 -11
- data/lib/onelogin/ruby-saml/settings.rb +132 -31
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +7 -6
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +7 -7
- data/lib/onelogin/ruby-saml/utils.rb +86 -22
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +116 -36
- data/ruby-saml.gemspec +6 -0
- metadata +4 -3
@@ -62,29 +62,14 @@ module OneLogin
|
|
62
62
|
}
|
63
63
|
end
|
64
64
|
|
65
|
-
# Add KeyDescriptor
|
66
|
-
# with SP certificate, and new SP certificate if any
|
65
|
+
# Add KeyDescriptor elements for SP certificates.
|
67
66
|
def add_sp_certificates(sp_sso, settings)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
kd = sp_sso.add_element "md:KeyDescriptor", { "use" => "signing" }
|
75
|
-
ki = kd.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
|
76
|
-
xd = ki.add_element "ds:X509Data"
|
77
|
-
xc = xd.add_element "ds:X509Certificate"
|
78
|
-
xc.text = cert_text
|
79
|
-
|
80
|
-
if settings.security[:want_assertions_encrypted]
|
81
|
-
kd2 = sp_sso.add_element "md:KeyDescriptor", { "use" => "encryption" }
|
82
|
-
ki2 = kd2.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
|
83
|
-
xd2 = ki2.add_element "ds:X509Data"
|
84
|
-
xc2 = xd2.add_element "ds:X509Certificate"
|
85
|
-
xc2.text = cert_text
|
86
|
-
end
|
87
|
-
end
|
67
|
+
certs = settings.get_sp_certs
|
68
|
+
|
69
|
+
certs[:signing].each { |cert, _| add_sp_cert_element(sp_sso, cert, :signing) }
|
70
|
+
|
71
|
+
if settings.security[:want_assertions_encrypted]
|
72
|
+
certs[:encryption].each { |cert, _| add_sp_cert_element(sp_sso, cert, :encryption) }
|
88
73
|
end
|
89
74
|
|
90
75
|
sp_sso
|
@@ -153,15 +138,14 @@ module OneLogin
|
|
153
138
|
def embed_signature(meta_doc, settings)
|
154
139
|
return unless settings.security[:metadata_signed]
|
155
140
|
|
156
|
-
private_key = settings.
|
157
|
-
cert = settings.get_sp_cert
|
141
|
+
cert, private_key = settings.get_sp_signing_pair
|
158
142
|
return unless private_key && cert
|
159
143
|
|
160
144
|
meta_doc.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
|
161
145
|
end
|
162
146
|
|
163
147
|
def output_xml(meta_doc, pretty_print)
|
164
|
-
ret = ''
|
148
|
+
ret = ''.dup
|
165
149
|
|
166
150
|
# pretty print the XML so IdP administrators can easily see what the SP supports
|
167
151
|
if pretty_print
|
@@ -172,6 +156,18 @@ module OneLogin
|
|
172
156
|
|
173
157
|
ret
|
174
158
|
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def add_sp_cert_element(sp_sso, cert, use)
|
163
|
+
return unless cert
|
164
|
+
cert_text = Base64.encode64(cert.to_der).gsub("\n", '')
|
165
|
+
kd = sp_sso.add_element "md:KeyDescriptor", { "use" => use.to_s }
|
166
|
+
ki = kd.add_element "ds:KeyInfo", { "xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#" }
|
167
|
+
xd = ki.add_element "ds:X509Data"
|
168
|
+
xc = xd.add_element "ds:X509Certificate"
|
169
|
+
xc.text = cert_text
|
170
|
+
end
|
175
171
|
end
|
176
172
|
end
|
177
173
|
end
|
@@ -17,6 +17,10 @@ module OneLogin
|
|
17
17
|
PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
|
18
18
|
DSIG = "http://www.w3.org/2000/09/xmldsig#"
|
19
19
|
XENC = "http://www.w3.org/2001/04/xmlenc#"
|
20
|
+
SAML_NAMESPACES = {
|
21
|
+
"p" => PROTOCOL,
|
22
|
+
"a" => ASSERTION
|
23
|
+
}.freeze
|
20
24
|
|
21
25
|
# TODO: Settings should probably be initialized too... WDYT?
|
22
26
|
|
@@ -198,6 +202,27 @@ module OneLogin
|
|
198
202
|
end
|
199
203
|
end
|
200
204
|
|
205
|
+
# Gets the AuthnInstant from the AuthnStatement.
|
206
|
+
# Could be used to require re-authentication if a long time has passed
|
207
|
+
# since the last user authentication.
|
208
|
+
# @return [String] AuthnInstant value
|
209
|
+
#
|
210
|
+
def authn_instant
|
211
|
+
@authn_instant ||= begin
|
212
|
+
node = xpath_first_from_signed_assertion('/a:AuthnStatement')
|
213
|
+
node.nil? ? nil : node.attributes['AuthnInstant']
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Gets the AuthnContextClassRef from the AuthnStatement
|
218
|
+
# Could be used to require re-authentication if the assertion
|
219
|
+
# did not met the requested authentication context class.
|
220
|
+
# @return [String] AuthnContextClassRef value
|
221
|
+
#
|
222
|
+
def authn_context_class_ref
|
223
|
+
@authn_context_class_ref ||= Utils.element_text(xpath_first_from_signed_assertion('/a:AuthnStatement/a:AuthnContext/a:AuthnContextClassRef'))
|
224
|
+
end
|
225
|
+
|
201
226
|
# Checks if the Status has the "Success" code
|
202
227
|
# @return [Boolean] True if the StatusCode is Sucess
|
203
228
|
#
|
@@ -282,7 +307,7 @@ module OneLogin
|
|
282
307
|
issuer_response_nodes = REXML::XPath.match(
|
283
308
|
document,
|
284
309
|
"/p:Response/a:Issuer",
|
285
|
-
|
310
|
+
SAML_NAMESPACES
|
286
311
|
)
|
287
312
|
|
288
313
|
unless issuer_response_nodes.size == 1
|
@@ -349,7 +374,7 @@ module OneLogin
|
|
349
374
|
! REXML::XPath.first(
|
350
375
|
document,
|
351
376
|
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
352
|
-
|
377
|
+
SAML_NAMESPACES
|
353
378
|
).nil?
|
354
379
|
end
|
355
380
|
|
@@ -380,9 +405,9 @@ module OneLogin
|
|
380
405
|
:validate_id,
|
381
406
|
:validate_success_status,
|
382
407
|
:validate_num_assertion,
|
383
|
-
:validate_no_duplicated_attributes,
|
384
408
|
:validate_signed_elements,
|
385
409
|
:validate_structure,
|
410
|
+
:validate_no_duplicated_attributes,
|
386
411
|
:validate_in_response_to,
|
387
412
|
:validate_one_conditions,
|
388
413
|
:validate_conditions,
|
@@ -423,12 +448,14 @@ module OneLogin
|
|
423
448
|
#
|
424
449
|
def validate_structure
|
425
450
|
structure_error_msg = "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
426
|
-
|
451
|
+
|
452
|
+
check_malformed_doc = check_malformed_doc_enabled?
|
453
|
+
unless valid_saml?(document, soft, check_malformed_doc)
|
427
454
|
return append_error(structure_error_msg)
|
428
455
|
end
|
429
456
|
|
430
457
|
unless decrypted_document.nil?
|
431
|
-
unless valid_saml?(decrypted_document, soft)
|
458
|
+
unless valid_saml?(decrypted_document, soft, check_malformed_doc)
|
432
459
|
return append_error(structure_error_msg)
|
433
460
|
end
|
434
461
|
end
|
@@ -812,7 +839,7 @@ module OneLogin
|
|
812
839
|
|
813
840
|
unless settings.sp_entity_id.nil? || settings.sp_entity_id.empty? || name_id_spnamequalifier.nil? || name_id_spnamequalifier.empty?
|
814
841
|
if name_id_spnamequalifier != settings.sp_entity_id
|
815
|
-
return append_error("
|
842
|
+
return append_error("SPNameQualifier value does not match the SP entityID value.")
|
816
843
|
end
|
817
844
|
end
|
818
845
|
end
|
@@ -820,6 +847,25 @@ module OneLogin
|
|
820
847
|
true
|
821
848
|
end
|
822
849
|
|
850
|
+
def doc_to_validate
|
851
|
+
# If the response contains the signature, and the assertion was encrypted, validate the original SAML Response
|
852
|
+
# otherwise, review if the decrypted assertion contains a signature
|
853
|
+
sig_elements = REXML::XPath.match(
|
854
|
+
document,
|
855
|
+
"/p:Response[@ID=$id]/ds:Signature",
|
856
|
+
{ "p" => PROTOCOL, "ds" => DSIG },
|
857
|
+
{ 'id' => document.signed_element_id }
|
858
|
+
)
|
859
|
+
|
860
|
+
use_original = sig_elements.size == 1 || decrypted_document.nil?
|
861
|
+
doc = use_original ? document : decrypted_document
|
862
|
+
if !doc.processed
|
863
|
+
doc.cache_referenced_xml(@soft, check_malformed_doc_enabled?)
|
864
|
+
end
|
865
|
+
|
866
|
+
return doc
|
867
|
+
end
|
868
|
+
|
823
869
|
# Validates the Signature
|
824
870
|
# @return [Boolean] True if not contains a Signature or if the Signature is valid, otherwise False if soft=True
|
825
871
|
# @raise [ValidationError] if soft == false and validation fails
|
@@ -827,8 +873,8 @@ module OneLogin
|
|
827
873
|
def validate_signature
|
828
874
|
error_msg = "Invalid Signature on SAML Response"
|
829
875
|
|
830
|
-
|
831
|
-
|
876
|
+
doc = doc_to_validate
|
877
|
+
|
832
878
|
sig_elements = REXML::XPath.match(
|
833
879
|
document,
|
834
880
|
"/p:Response[@ID=$id]/ds:Signature",
|
@@ -836,15 +882,12 @@ module OneLogin
|
|
836
882
|
{ 'id' => document.signed_element_id }
|
837
883
|
)
|
838
884
|
|
839
|
-
|
840
|
-
doc = use_original ? document : decrypted_document
|
841
|
-
|
842
|
-
# Check signature nodes
|
885
|
+
# Check signature node inside assertion
|
843
886
|
if sig_elements.nil? || sig_elements.size == 0
|
844
887
|
sig_elements = REXML::XPath.match(
|
845
888
|
doc,
|
846
889
|
"/p:Response/a:Assertion[@ID=$id]/ds:Signature",
|
847
|
-
{"
|
890
|
+
SAML_NAMESPACES.merge({"ds"=>DSIG}),
|
848
891
|
{ 'id' => doc.signed_element_id }
|
849
892
|
)
|
850
893
|
end
|
@@ -915,31 +958,54 @@ module OneLogin
|
|
915
958
|
begin
|
916
959
|
encrypted_node = xpath_first_from_signed_assertion('/a:Subject/a:EncryptedID')
|
917
960
|
if encrypted_node
|
918
|
-
|
961
|
+
decrypt_nameid(encrypted_node)
|
919
962
|
else
|
920
|
-
|
963
|
+
xpath_first_from_signed_assertion('/a:Subject/a:NameID')
|
921
964
|
end
|
922
965
|
end
|
923
966
|
end
|
924
967
|
|
968
|
+
def get_cached_signed_assertion
|
969
|
+
xml = doc_to_validate.referenced_xml
|
970
|
+
empty_doc = REXML::Document.new
|
971
|
+
|
972
|
+
return empty_doc if xml.nil? # when no signature/reference is found, return empty document
|
973
|
+
|
974
|
+
root = REXML::Document.new(xml).root
|
975
|
+
|
976
|
+
if root.attributes["ID"] != doc_to_validate.signed_element_id
|
977
|
+
return empty_doc
|
978
|
+
end
|
979
|
+
|
980
|
+
assertion = empty_doc
|
981
|
+
if root.name == "Response"
|
982
|
+
if REXML::XPath.first(root, "a:Assertion", {"a" => ASSERTION})
|
983
|
+
assertion = REXML::XPath.first(root, "a:Assertion", {"a" => ASSERTION})
|
984
|
+
elsif REXML::XPath.first(root, "a:EncryptedAssertion", {"a" => ASSERTION})
|
985
|
+
assertion = decrypt_assertion(REXML::XPath.first(root, "a:EncryptedAssertion", {"a" => ASSERTION}))
|
986
|
+
end
|
987
|
+
elsif root.name == "Assertion"
|
988
|
+
assertion = root
|
989
|
+
end
|
990
|
+
|
991
|
+
assertion
|
992
|
+
end
|
993
|
+
|
994
|
+
def signed_assertion
|
995
|
+
@signed_assertion ||= get_cached_signed_assertion
|
996
|
+
end
|
997
|
+
|
925
998
|
# Extracts the first appearance that matchs the subelt (pattern)
|
926
999
|
# Search on any Assertion that is signed, or has a Response parent signed
|
927
1000
|
# @param subelt [String] The XPath pattern
|
928
1001
|
# @return [REXML::Element | nil] If any matches, return the Element
|
929
1002
|
#
|
930
1003
|
def xpath_first_from_signed_assertion(subelt=nil)
|
931
|
-
doc =
|
1004
|
+
doc = signed_assertion
|
932
1005
|
node = REXML::XPath.first(
|
933
1006
|
doc,
|
934
|
-
"
|
935
|
-
|
936
|
-
{ 'id' => doc.signed_element_id }
|
937
|
-
)
|
938
|
-
node ||= REXML::XPath.first(
|
939
|
-
doc,
|
940
|
-
"/p:Response[@ID=$id]/a:Assertion#{subelt}",
|
941
|
-
{ "p" => PROTOCOL, "a" => ASSERTION },
|
942
|
-
{ 'id' => doc.signed_element_id }
|
1007
|
+
"./#{subelt}",
|
1008
|
+
SAML_NAMESPACES
|
943
1009
|
)
|
944
1010
|
node
|
945
1011
|
end
|
@@ -950,26 +1016,20 @@ module OneLogin
|
|
950
1016
|
# @return [Array of REXML::Element] Return all matches
|
951
1017
|
#
|
952
1018
|
def xpath_from_signed_assertion(subelt=nil)
|
953
|
-
doc =
|
1019
|
+
doc = signed_assertion
|
954
1020
|
node = REXML::XPath.match(
|
955
1021
|
doc,
|
956
|
-
"
|
957
|
-
|
958
|
-
{ 'id' => doc.signed_element_id }
|
1022
|
+
"./#{subelt}",
|
1023
|
+
SAML_NAMESPACES
|
959
1024
|
)
|
960
|
-
node
|
961
|
-
doc,
|
962
|
-
"/p:Response[@ID=$id]/a:Assertion#{subelt}",
|
963
|
-
{ "p" => PROTOCOL, "a" => ASSERTION },
|
964
|
-
{ 'id' => doc.signed_element_id }
|
965
|
-
))
|
1025
|
+
node
|
966
1026
|
end
|
967
1027
|
|
968
1028
|
# Generates the decrypted_document
|
969
1029
|
# @return [XMLSecurity::SignedDocument] The SAML Response with the assertion decrypted
|
970
1030
|
#
|
971
1031
|
def generate_decrypted_document
|
972
|
-
if settings.nil? ||
|
1032
|
+
if settings.nil? || settings.get_sp_decryption_keys.empty?
|
973
1033
|
raise ValidationError.new('An EncryptedAssertion found and no SP private key found on the settings to decrypt it. Be sure you provided the :settings parameter at the initialize method')
|
974
1034
|
end
|
975
1035
|
|
@@ -996,7 +1056,7 @@ module OneLogin
|
|
996
1056
|
encrypted_assertion_node = REXML::XPath.first(
|
997
1057
|
document_copy,
|
998
1058
|
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
999
|
-
|
1059
|
+
SAML_NAMESPACES
|
1000
1060
|
)
|
1001
1061
|
response_node.add(decrypt_assertion(encrypted_assertion_node))
|
1002
1062
|
encrypted_assertion_node.remove
|
@@ -1012,42 +1072,42 @@ module OneLogin
|
|
1012
1072
|
end
|
1013
1073
|
|
1014
1074
|
# Decrypts an EncryptedID element
|
1015
|
-
# @param
|
1075
|
+
# @param encrypted_id_node [REXML::Element] The EncryptedID element
|
1016
1076
|
# @return [REXML::Document] The decrypted EncrypedtID element
|
1017
1077
|
#
|
1018
|
-
def decrypt_nameid(
|
1019
|
-
decrypt_element(
|
1078
|
+
def decrypt_nameid(encrypted_id_node)
|
1079
|
+
decrypt_element(encrypted_id_node, /(.*<\/(\w+:)?NameID>)/m)
|
1020
1080
|
end
|
1021
1081
|
|
1022
|
-
# Decrypts an
|
1023
|
-
# @param
|
1024
|
-
# @return [REXML::Document] The decrypted
|
1082
|
+
# Decrypts an EncryptedAttribute element
|
1083
|
+
# @param encrypted_attribute_node [REXML::Element] The EncryptedAttribute element
|
1084
|
+
# @return [REXML::Document] The decrypted EncryptedAttribute element
|
1025
1085
|
#
|
1026
|
-
def decrypt_attribute(
|
1027
|
-
decrypt_element(
|
1086
|
+
def decrypt_attribute(encrypted_attribute_node)
|
1087
|
+
decrypt_element(encrypted_attribute_node, /(.*<\/(\w+:)?Attribute>)/m)
|
1028
1088
|
end
|
1029
1089
|
|
1030
1090
|
# Decrypt an element
|
1031
|
-
# @param
|
1032
|
-
# @param
|
1091
|
+
# @param encrypt_node [REXML::Element] The encrypted element
|
1092
|
+
# @param regexp [Regexp] The regular expression to extract the decrypted data
|
1033
1093
|
# @return [REXML::Document] The decrypted element
|
1034
1094
|
#
|
1035
|
-
def decrypt_element(encrypt_node,
|
1036
|
-
if settings.nil? ||
|
1095
|
+
def decrypt_element(encrypt_node, regexp)
|
1096
|
+
if settings.nil? || settings.get_sp_decryption_keys.empty?
|
1037
1097
|
raise ValidationError.new('An ' + encrypt_node.name + ' found and no SP private key found on the settings to decrypt it')
|
1038
1098
|
end
|
1039
1099
|
|
1040
|
-
|
1041
1100
|
if encrypt_node.name == 'EncryptedAttribute'
|
1042
1101
|
node_header = '<node xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
1043
1102
|
else
|
1044
1103
|
node_header = '<node xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">'
|
1045
1104
|
end
|
1046
1105
|
|
1047
|
-
elem_plaintext = OneLogin::RubySaml::Utils.
|
1106
|
+
elem_plaintext = OneLogin::RubySaml::Utils.decrypt_multi(encrypt_node, settings.get_sp_decryption_keys)
|
1107
|
+
|
1048
1108
|
# If we get some problematic noise in the plaintext after decrypting.
|
1049
1109
|
# This quick regexp parse will grab only the Element and discard the noise.
|
1050
|
-
elem_plaintext = elem_plaintext.match(
|
1110
|
+
elem_plaintext = elem_plaintext.match(regexp)[0]
|
1051
1111
|
|
1052
1112
|
# To avoid namespace errors if saml namespace is not defined
|
1053
1113
|
# create a parent node first with the namespace defined
|
@@ -1066,6 +1126,10 @@ module OneLogin
|
|
1066
1126
|
Time.parse(node.attributes[attribute])
|
1067
1127
|
end
|
1068
1128
|
end
|
1129
|
+
|
1130
|
+
def check_malformed_doc_enabled?
|
1131
|
+
check_malformed_doc?(settings)
|
1132
|
+
end
|
1069
1133
|
end
|
1070
1134
|
end
|
1071
1135
|
end
|
@@ -19,15 +19,13 @@ module OneLogin
|
|
19
19
|
PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol".freeze
|
20
20
|
|
21
21
|
BASE64_FORMAT = %r(\A([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z)
|
22
|
-
@@mutex = Mutex.new
|
23
22
|
|
24
23
|
# @return [Nokogiri::XML::Schema] Gets the schema object of the SAML 2.0 Protocol schema
|
25
24
|
#
|
26
25
|
def self.schema
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
26
|
+
path = File.expand_path("../../../schemas/saml-schema-protocol-2.0.xsd", __FILE__)
|
27
|
+
File.open(path) do |file|
|
28
|
+
::Nokogiri::XML::Schema(file)
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
@@ -60,14 +58,13 @@ module OneLogin
|
|
60
58
|
# Validates the SAML Message against the specified schema.
|
61
59
|
# @param document [REXML::Document] The message that will be validated
|
62
60
|
# @param soft [Boolean] soft Enable or Disable the soft mode (In order to raise exceptions when the message is invalid or not)
|
61
|
+
# @param check_malformed_doc [Boolean] check_malformed_doc Enable or Disable the check for malformed XML
|
63
62
|
# @return [Boolean] True if the XML is valid, otherwise False, if soft=True
|
64
63
|
# @raise [ValidationError] if soft == false and validation fails
|
65
64
|
#
|
66
|
-
def valid_saml?(document, soft = true)
|
65
|
+
def valid_saml?(document, soft = true, check_malformed_doc = true)
|
67
66
|
begin
|
68
|
-
xml =
|
69
|
-
config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS
|
70
|
-
end
|
67
|
+
xml = XMLSecurity::BaseDocument.safe_load_xml(document, check_malformed_doc)
|
71
68
|
rescue StandardError => error
|
72
69
|
return false if soft
|
73
70
|
raise ValidationError.new("XML load failed: #{error.message}")
|
@@ -83,6 +80,7 @@ module OneLogin
|
|
83
80
|
|
84
81
|
# Base64 decode and try also to inflate a SAML Message
|
85
82
|
# @param saml [String] The deflated and encoded SAML Message
|
83
|
+
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
86
84
|
# @return [String] The plain SAML Message
|
87
85
|
#
|
88
86
|
def decode_raw_saml(saml, settings = nil)
|
@@ -95,10 +93,16 @@ module OneLogin
|
|
95
93
|
|
96
94
|
decoded = decode(saml)
|
97
95
|
begin
|
98
|
-
|
96
|
+
message = inflate(decoded)
|
99
97
|
rescue
|
100
|
-
|
98
|
+
message = decoded
|
99
|
+
end
|
100
|
+
|
101
|
+
if message.bytesize > settings.message_max_bytesize
|
102
|
+
raise ValidationError.new("SAML Message exceeds " + settings.message_max_bytesize.to_s + " bytes, so was rejected")
|
101
103
|
end
|
104
|
+
|
105
|
+
message
|
102
106
|
end
|
103
107
|
|
104
108
|
# Deflate, base64 encode and url-encode a SAML Message (To be used in the HTTP-redirect binding)
|
@@ -155,6 +159,12 @@ module OneLogin
|
|
155
159
|
def deflate(inflated)
|
156
160
|
Zlib::Deflate.deflate(inflated, 9)[2..-5]
|
157
161
|
end
|
162
|
+
|
163
|
+
def check_malformed_doc?(settings)
|
164
|
+
default_value = OneLogin::RubySaml::Settings::DEFAULTS[:check_malformed_doc]
|
165
|
+
|
166
|
+
settings.nil? ? default_value : settings.check_malformed_doc
|
167
|
+
end
|
158
168
|
end
|
159
169
|
end
|
160
170
|
end
|