@@ -18,7 +18,7 @@ class SamlMessage
1818 ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion" . freeze
1919 PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol" . freeze
2020
21- BASE64_FORMAT = %r( \A ([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z )
21+ BASE64_FORMAT = %r{ \A ([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z }
2222
2323 # @return [Nokogiri::XML::Schema] Gets the schema object of the SAML 2.0 Protocol schema
2424 #
@@ -91,18 +91,13 @@ def decode_raw_saml(saml, settings = nil)
9191
9292 return saml unless base64_encoded? ( saml )
9393
94- decoded = decode ( saml )
95- begin
96- message = inflate ( decoded )
97- rescue
98- message = decoded
99- end
94+ saml = try_inflate ( decode ( saml ) , settings . message_max_bytesize )
10095
101- if message . bytesize > settings . message_max_bytesize
96+ if saml . bytesize > settings . message_max_bytesize
10297 raise ValidationError . new ( "SAML Message exceeds " + settings . message_max_bytesize . to_s + " bytes, so was rejected" )
10398 end
10499
105- message
100+ saml
106101 end
107102
108103 # Deflate, base64 encode and url-encode a SAML Message (To be used in the HTTP-redirect binding)
@@ -144,12 +139,50 @@ def base64_encoded?(string)
144139 !!string . gsub ( /[\r \n ]|\\ r|\\ n|\s / , "" ) . match ( BASE64_FORMAT )
145140 end
146141
147- # Inflate method
142+ # Attempt inflating a string, if it fails, return the original string.
143+ # @param data [String] The string
144+ # @param max_bytesize [Integer] The maximum allowed size of the SAML Message,
145+ # to prevent a possible DoS attack.
146+ # @return [String] The inflated or original string
147+ def try_inflate ( data , max_bytesize = nil )
148+ inflate ( data , max_bytesize )
149+ rescue Zlib ::Error
150+ data
151+ end
152+
153+ # Inflate method.
148154 # @param deflated [String] The string
155+ # @param max_bytesize [Integer] The maximum allowed size of the SAML Message,
156+ # to prevent a possible DoS attack.
149157 # @return [String] The inflated string
150- #
151- def inflate ( deflated )
152- Zlib ::Inflate . new ( -Zlib ::MAX_WBITS ) . inflate ( deflated )
158+ def inflate ( deflated , max_bytesize = nil )
159+ unless max_bytesize . nil?
160+ inflater = Zlib ::Inflate . new ( -Zlib ::MAX_WBITS )
161+
162+ # Use a StringIO buffer to build the inflated message incrementally.
163+ buffer = StringIO . new
164+
165+ inflater . inflate ( deflated ) do |chunk |
166+ if buffer . length + chunk . bytesize > max_bytesize
167+ inflater . close
168+ raise ValidationError , "SAML Message exceeds #{ max_bytesize } bytes during decompression, so was rejected"
169+ end
170+ buffer << chunk
171+ end
172+
173+ final_chunk = inflater . finish
174+ unless final_chunk . empty?
175+ if buffer . length + final_chunk . bytesize > max_bytesize
176+ raise ValidationError , "SAML Message exceeds #{ max_bytesize } bytes during decompression, so was rejected"
177+ end
178+ buffer << final_chunk
179+ end
180+
181+ inflater . close
182+ buffer . string
183+ else
184+ Zlib ::Inflate . new ( -Zlib ::MAX_WBITS ) . inflate ( deflated )
185+ end
153186 end
154187
155188 # Deflate method
0 commit comments