@@ -229,18 +229,48 @@ def validate_signature
229229 return true unless options . has_key? :get_params
230230 return true unless options [ :get_params ] . has_key? 'Signature'
231231
232+ # SAML specifies that the signature should be derived from a concatenation
233+ # of URI-encoded values _as sent by the IDP_:
234+ #
235+ # > Further, note that URL-encoding is not canonical; that is, there are multiple legal encodings for a given
236+ # > value. The relying party MUST therefore perform the verification step using the original URL-encoded
237+ # > values it received on the query string. It is not sufficient to re-encode the parameters after they have been
238+ # > processed by software because the resulting encoding may not match the signer's encoding.
239+ #
240+ # <http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf>
241+ #
242+ # If we don't have the original parts (for backward compatibility) required to correctly verify the signature,
243+ # then fabricate them by re-encoding the parsed URI parameters, and hope that we're lucky enough to use
244+ # the exact same URI-encoding as the IDP. (This is not the case if the IDP is ADFS!)
245+ options [ :raw_get_params ] ||= { }
246+ if options [ :raw_get_params ] [ 'SAMLRequest' ] . nil? && !options [ :get_params ] [ 'SAMLRequest' ] . nil?
247+ options [ :raw_get_params ] [ 'SAMLRequest' ] = CGI . escape ( options [ :get_params ] [ 'SAMLRequest' ] )
248+ end
249+ if options [ :raw_get_params ] [ 'RelayState' ] . nil? && !options [ :get_params ] [ 'RelayState' ] . nil?
250+ options [ :raw_get_params ] [ 'RelayState' ] = CGI . escape ( options [ :get_params ] [ 'RelayState' ] )
251+ end
252+ if options [ :raw_get_params ] [ 'SigAlg' ] . nil? && !options [ :get_params ] [ 'SigAlg' ] . nil?
253+ options [ :raw_get_params ] [ 'SigAlg' ] = CGI . escape ( options [ :get_params ] [ 'SigAlg' ] )
254+ end
255+
256+ # If we only received the raw version of SigAlg,
257+ # then parse it back into the decoded params hash for convenience.
258+ if options [ :get_params ] [ 'SigAlg' ] . nil? && !options [ :raw_get_params ] [ 'SigAlg' ] . nil?
259+ options [ :get_params ] [ 'SigAlg' ] = CGI . unescape ( options [ :raw_get_params ] [ 'SigAlg' ] )
260+ end
261+
232262 idp_cert = settings . get_idp_cert
233263 idp_certs = settings . get_idp_cert_multi
234264
235265 if idp_cert . nil? && ( idp_certs . nil? || idp_certs [ :signing ] . empty? )
236266 return options . has_key? :relax_signature_validation
237267 end
238268
239- query_string = OneLogin ::RubySaml ::Utils . build_query (
240- :type => 'SAMLRequest' ,
241- :data => options [ :get_params ] [ 'SAMLRequest' ] ,
242- :relay_state => options [ :get_params ] [ 'RelayState' ] ,
243- :sig_alg => options [ :get_params ] [ 'SigAlg' ]
269+ query_string = OneLogin ::RubySaml ::Utils . build_query_from_raw_parts (
270+ :type => 'SAMLRequest' ,
271+ :raw_data => options [ :raw_get_params ] [ 'SAMLRequest' ] ,
272+ :raw_relay_state => options [ :raw_get_params ] [ 'RelayState' ] ,
273+ :raw_sig_alg => options [ :raw_get_params ] [ 'SigAlg' ]
244274 )
245275
246276 if idp_certs . nil? || idp_certs [ :signing ] . empty?
0 commit comments