Login redirect sends incorrect HTTP headers, causing Safari to error

Created on 25 September 2020, almost 4 years ago
Updated 24 May 2023, about 1 year ago

Problem/Motivation

On safari the login redirect (if an oauth authorization is requested but the user is not logged in) does not seem to work. Both on iOS and OSX. It can result in a `Safari can't open the page` message or an NSPOSIXErrorDomain:100 error. Most other browsers do not seem to stumble on this problem.

This happens on an Apache 2.4.46 server with PHP 7.3.

Steps to reproduce

Curl also seems to indicate the problem, and so it can be reproduced as for instance:
curl -v 'https://DOMAIN/oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...'
which results in an error that the stream was not closed cleanly.

* Connected to <snip> port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=<snip>
*  start date: Aug 31 10:23:38 2020 GMT
*  expire date: Nov 29 10:23:38 2020 GMT
*  subjectAltName: host "<snip>" matched cert's "<snip>"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x561ec25799f0)
> GET /oauth/authorize?response_type=code&client_id=<snip>&redirect_uri=<snip>&state=<snip> HTTP/2
> Host: <snip>
> user-agent: curl/7.72.0
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 302 
< date: Thu, 24 Sep 2020 21:29:13 GMT
< server: Apache
< x-powered-by: PHP/7.3.22
< accept: */*
< host: <snip>
< user-agent: curl/7.72.0
< x-https: 1
< authorization: 
< x-php-ob-level: 0
< cache-control: must-revalidate, no-cache, private
< x-ua-compatible: IE=edge
< content-language: en
< x-content-type-options: nosniff
< x-frame-options: SAMEORIGIN
< expires: Sun, 19 Nov 1978 05:00:00 GMT
< x-generator: Drupal 8 (https://www.drupal.org)
< strict-transport-security: max-age=1000
< set-cookie: <snip>
< content-length: 0
< location: /user/login?destination=/oauth/authorize%3Fclient_id%3<snip>%26redirect_uri%3D<snip>%26response_type%3Dcode%26state%<snip>
< content-type: text/html; charset=UTF-8
< 
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!
* Connection #0 to host <snip> left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)

This seems to me to be because a content-length of 0 was given, but drupal actually provides a little bit of HTML with the redirect.

Proposed resolution

If the user is not logged in a redirectResponse is created, with in it the request headers. It seems to be that the request headers are not necessary there.
return RedirectResponse::create($url->toString(), 302), $request->headers->all());
Removing $request->headers->all() from this seems to prevent the problem, resulting in curl output like:

[snipped some of the HTTPS stuff]
< HTTP/2 302 
< date: Thu, 24 Sep 2020 21:32:07 GMT
< server: Apache
< x-powered-by: PHP/7.3.22
< cache-control: must-revalidate, no-cache, private
< x-ua-compatible: IE=edge
< content-language: en
< x-content-type-options: nosniff
< x-frame-options: SAMEORIGIN
< expires: Sun, 19 Nov 1978 05:00:00 GMT
< x-generator: Drupal 8 (https://www.drupal.org)
< strict-transport-security: max-age=1000
< set-cookie: <snip>
< location: /user/login?destination=/oauth/authorize%3Fclient_id%3D<snip>%26redirect_uri%3D<snip>%26response_type%3Dcode%26state%3D<snip>
< content-type: text/html; charset=UTF-8
< 
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url='/user/login?destination=/oauth/authorize<snip>" />

        <title>Redirecting to /user/login?destination=/oauth/authorize<snip></title>
    </head>
    <body>
        Redirecting to <a href="/user/login?destination=/oauth/authorize%3Fclient_id%<snip>">/user/login?destination=/oauth/authorize<snip></a>.
    </body>
* Connection #0 to host <snip> left intact
</html>
πŸ› Bug report
Status

Fixed

Version

6.0

Component

Code

Created by

πŸ‡³πŸ‡±Netherlands Exteris

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.69.0 2024