Skip to content

Commit

Permalink
cabal-install: update curl transport to support Basic authentication (#…
Browse files Browse the repository at this point in the history
…10089)

* cabal-install: extract url scheme checks

Extract a bunch of string equality checks for the URI scheme to
top-level functions.

* cabal-install: refactor and document transport checks

"They're the same picture".  Thus, refactor the *transport supports
https* checks.

* cabal-install: allow Basic authentication in curl transport

Allow the curl transport to use Basic authentication, if and only if
the url scheme is HTTPS (i.e. TLS will be used).  Retain the
existing behaviour (force Digest scheme) for insecure requests.

This change is required to support upcoming hackage-server changes.
The wget transport already supports Basic authentication.

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
frasertweedale and mergify[bot] authored Aug 22, 2024
1 parent a1c94c1 commit fb2ac8c
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 12 deletions.
45 changes: 33 additions & 12 deletions cabal-install/src/Distribution/Client/HttpUtils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ downloadURI transport verbosity uri path = do
-- Only use the external http transports if we actually have to
-- (or have been told to do so)
let transport'
| uriScheme uri == "http:"
| isHttpURI uri
, not (transportManuallySelected transport) =
plainHttpTransport
| otherwise =
Expand Down Expand Up @@ -251,20 +251,35 @@ downloadURI transport verbosity uri path = do
-- Utilities for repo url management
--

-- | If the remote repo is accessed over HTTPS, ensure that the transport
-- supports HTTPS.
remoteRepoCheckHttps :: Verbosity -> HttpTransport -> RemoteRepo -> IO ()
remoteRepoCheckHttps verbosity transport repo
| uriScheme (remoteRepoURI repo) == "https:"
, not (transportSupportsHttps transport) =
dieWithException verbosity $ RemoteRepoCheckHttps (unRepoName (remoteRepoName repo)) requiresHttpsErrorMessage
| otherwise = return ()
remoteRepoCheckHttps verbosity transport repo =
transportCheckHttpsWithError verbosity transport (remoteRepoURI repo) $
RemoteRepoCheckHttps (unRepoName (remoteRepoName repo)) requiresHttpsErrorMessage

-- | If the URI scheme is HTTPS, ensure the transport supports HTTPS.
transportCheckHttps :: Verbosity -> HttpTransport -> URI -> IO ()
transportCheckHttps verbosity transport uri
| uriScheme uri == "https:"
transportCheckHttps verbosity transport uri =
transportCheckHttpsWithError verbosity transport uri $
TransportCheckHttps uri requiresHttpsErrorMessage

-- | If the URI scheme is HTTPS, ensure the transport supports HTTPS.
-- If not, fail with the given error.
transportCheckHttpsWithError
:: Verbosity -> HttpTransport -> URI -> CabalInstallException -> IO ()
transportCheckHttpsWithError verbosity transport uri err
| isHttpsURI uri
, not (transportSupportsHttps transport) =
dieWithException verbosity $ TransportCheckHttps uri requiresHttpsErrorMessage
dieWithException verbosity err
| otherwise = return ()

isHttpsURI :: URI -> Bool
isHttpsURI uri = uriScheme uri == "https:"

isHttpURI :: URI -> Bool
isHttpURI uri = uriScheme uri == "http:"

requiresHttpsErrorMessage :: String
requiresHttpsErrorMessage =
"requires HTTPS however the built-in HTTP implementation "
Expand All @@ -280,12 +295,12 @@ requiresHttpsErrorMessage =
remoteRepoTryUpgradeToHttps :: Verbosity -> HttpTransport -> RemoteRepo -> IO RemoteRepo
remoteRepoTryUpgradeToHttps verbosity transport repo
| remoteRepoShouldTryHttps repo
, uriScheme (remoteRepoURI repo) == "http:"
, isHttpURI (remoteRepoURI repo)
, not (transportSupportsHttps transport)
, not (transportManuallySelected transport) =
dieWithException verbosity $ TryUpgradeToHttps [name | (name, _, True, _) <- supportedTransports]
| remoteRepoShouldTryHttps repo
, uriScheme (remoteRepoURI repo) == "http:"
, isHttpURI (remoteRepoURI repo)
, transportSupportsHttps transport =
return
repo
Expand Down Expand Up @@ -505,12 +520,18 @@ curlTransport prog =
(Just (Left (uname, passwd)), _) -> Just $ Left (uname ++ ":" ++ passwd)
(Nothing, Just a) -> Just $ Left a
(Nothing, Nothing) -> Nothing
let authnSchemeArg
-- When using TLS, we can accept Basic authentication. Let curl
-- decide based on the scheme(s) offered by the server.
| isHttpsURI uri = "--anyauth"
-- When not using TLS, force Digest scheme
| otherwise = "--digest"
case mbAuthStringToken of
Just (Left up) ->
progInvocation
{ progInvokeInput =
Just . IODataText . unlines $
[ "--digest"
[ authnSchemeArg
, "--user " ++ up
]
, progInvokeArgs = ["--config", "-"] ++ progInvokeArgs progInvocation
Expand Down
12 changes: 12 additions & 0 deletions changelog.d/pr-10089
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
synopsis: `curl` transport now supports Basic authentication
packages: cabal-install
prs: #10089

description: {

- The `curl` HTTP transport previously only supported the HTTP Digest
authentication scheme. Basic authentication is now supported
when using HTTPS; Curl will use the scheme offered by the server.
The `wget` transport already supports HTTPS.

}

0 comments on commit fb2ac8c

Please sign in to comment.