]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[http] Work around stateful authentication schemes
authorMichael Brown <mcb30@ipxe.org>
Mon, 14 May 2018 10:16:34 +0000 (11:16 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 8 Jun 2018 12:53:02 +0000 (13:53 +0100)
As pointedly documented in RFC7230 section 2.3, HTTP is a stateless
protocol: each request message can be understood in isolation from any
other requests or responses.  Various authentication schemes such as
NTLM break this fundamental property of HTTP and rely on the same TCP
connection being reused.

Work around these broken authentication schemes by ensuring that the
most recently pooled connection is reused for the subsequent
authentication retry.

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/net/tcp/httpconn.c
src/net/tcp/httpcore.c

index 2cfca9c94b7de4a00414a1e7416c143284056636..5121ff6c221e398b578aab69fe08d59c95825e9e 100644 (file)
@@ -252,8 +252,13 @@ int http_connect ( struct interface *xfer, struct uri *uri ) {
        /* Identify port */
        port = uri_port ( uri, scheme->port );
 
-       /* Look for a reusable connection in the pool */
-       list_for_each_entry ( conn, &http_connection_pool, pool.list ) {
+       /* Look for a reusable connection in the pool.  Reuse the most
+        * recent connection in order to accommodate authentication
+        * schemes that break the stateless nature of HTTP and rely on
+        * the same connection being reused for authentication
+        * responses.
+        */
+       list_for_each_entry_reverse ( conn, &http_connection_pool, pool.list ) {
 
                /* Sanity checks */
                assert ( conn->uri != NULL );
index b3c9a00e6c126cc6312f22a749e4e9c06d9e0382..f755fb72d00896140bd7cd235db899ef9bb69f27 100644 (file)
@@ -778,6 +778,18 @@ static int http_transfer_complete ( struct http_transaction *http ) {
        http->len = 0;
        assert ( http->remaining == 0 );
 
+       /* Retry immediately if applicable.  We cannot rely on an
+        * immediate timer expiry, since certain Microsoft-designed
+        * HTTP extensions such as NTLM break the fundamentally
+        * stateless nature of HTTP and rely on the same connection
+        * being reused for authentication.  See RFC7230 section 2.3
+        * for further details.
+        */
+       if ( ! http->response.retry_after ) {
+               http_reopen ( http );
+               return 0;
+       }
+
        /* Start timer to initiate retry */
        DBGC2 ( http, "HTTP %p retrying after %d seconds\n",
                http, http->response.retry_after );