ucb/source/ucp/webdav-curl/CurlSession.cxx |   63 +++++++++++++++++++++++------
 1 file changed, 50 insertions(+), 13 deletions(-)

New commits:
commit d7492813058bff81c17068feee0e4ba7627c17de
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Mar 7 18:38:22 2024 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri Mar 8 15:18:49 2024 +0100

    ucb: webdav-curl: try fallback authentication on 403 error
    
    Sharepoint reports lack of authentication with 403 status and additional
    X-MSDAVEXT_ERROR header value 0x000E0098.
    
    Try to add the magic header "X-FORMS_BASED_AUTH_ACCEPTED: f" and
    fallback to Negotiate auth in this case; this requires cookies to be
    enabled.
    
    Note that the build config of libcurl on Linux is such that adding
    CURLAUTH_NEGOTIATE has no effect, but on WNT having both NEGOTIATE
    and NTLM causes the AuthMask to be ambiguous and prevents curl from
    trying.
    
    Change-Id: I47dada2ef08b21a43cdfa3db9eb2fcdb4043a04f
    Change-Id: Ia3e31c994bde0f8db84a60931702323c94c02e0e
    (cherry picked from commit c6df10ce7f91b3084255bfbbac95e865bbb3ce7b)
    Change-Id: I93e0c8f95beafc30b94296430352f2ae54e65b11
    (cherry picked from commit 37abfd767874441568d9f5ac499b2d93d34e10fe)
    Change-Id: I0018a9904857d7521895936dc27607a54523f300
    (cherry picked from commit 388a702af2fe45b2c436e64eb8639f16c1e24b76)
    Change-Id: Iafa8bdd183ef8a514b656ec41a9b7a6fa1e3acb9
    (cherry picked from commit e84c21aca4b72d9e86c856f717b3bf1b75f190af)
    
    Change-Id: I6dfcb3ba6e44bbb76bc403e30b4a7b6ee95296f5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164551
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/ucb/source/ucp/webdav-curl/CurlSession.cxx 
b/ucb/source/ucp/webdav-curl/CurlSession.cxx
index 4096115a40aa..342ba3669699 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.cxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.cxx
@@ -1386,6 +1386,31 @@ auto CurlProcessor::ProcessRequest(
                         }
                         break;
                     }
+                    case SC_FORBIDDEN:
+                    {
+                        ::std::map<OUString, OUString> const headerMap(
+                            ProcessHeaders(headers.HeaderFields.back().first));
+                        // X-MSDAVEXT_Error see [MS-WEBDAVE] 2.2.3.1.9
+                        auto const it(headerMap.find("x-msdavext_error"));
+                        if (it == headerMap.end() || 
!it->second.startsWith("917656;"))
+                        {
+                            break;
+                        }
+                        // fallback needs cookie engine enabled
+                        CURLcode rc
+                            = curl_easy_setopt(rSession.m_pCurl.get(), 
CURLOPT_COOKIEFILE, "");
+                        assert(rc == CURLE_OK);
+                        (void)rc;
+                        SAL_INFO("ucb.ucp.webdav.curl", "403 fallback 
authentication");
+                        // disable 302 redirect
+                        pRequestHeaderList.reset(curl_slist_append(
+                            pRequestHeaderList.release(), 
"X-FORMS_BASED_AUTH_ACCEPTED: f"));
+                        if (!pRequestHeaderList)
+                        {
+                            throw uno::RuntimeException("curl_slist_append 
failed");
+                        }
+                    }
+                        [[fallthrough]]; // SP, no cookie, or cookie failed: 
try NTLM/Negotiate
                     case SC_UNAUTHORIZED:
                     case SC_PROXY_AUTHENTICATION_REQUIRED:
                     {
@@ -1393,8 +1418,9 @@ auto CurlProcessor::ProcessRequest(
                              ? rSession.m_isAuthenticated
                              : rSession.m_isAuthenticatedProxy)
                             = false; // any auth data in m_pCurl is invalid
-                        auto& rnAuthRequests(statusCode == SC_UNAUTHORIZED ? 
nAuthRequests
-                                                                           : 
nAuthRequestsProxy);
+                        auto& rnAuthRequests(statusCode != 
SC_PROXY_AUTHENTICATION_REQUIRED
+                                                 ? nAuthRequests
+                                                 : nAuthRequestsProxy);
                         if (rnAuthRequests == 10)
                         {
                             SAL_INFO("ucb.ucp.webdav.curl", "aborting 
authentication after "
@@ -1402,22 +1428,32 @@ auto CurlProcessor::ProcessRequest(
                         }
                         else if (pEnv && pEnv->m_xAuthListener)
                         {
-                            ::std::optional<OUString> const 
oRealm(ExtractRealm(
-                                headers, statusCode == SC_UNAUTHORIZED ? 
"WWW-Authenticate"
-                                                                       : 
"Proxy-Authenticate"));
+                            ::std::optional<OUString> const oRealm(
+                                ExtractRealm(headers, statusCode != 
SC_PROXY_AUTHENTICATION_REQUIRED
+                                                          ? "WWW-Authenticate"
+                                                          : 
"Proxy-Authenticate"));
 
                             ::std::optional<Auth>& roAuth(
-                                statusCode == SC_UNAUTHORIZED ? oAuth : 
oAuthProxy);
+                                statusCode != SC_PROXY_AUTHENTICATION_REQUIRED 
? oAuth
+                                                                               
: oAuthProxy);
                             OUString userName(roAuth ? roAuth->UserName : 
OUString());
                             OUString passWord(roAuth ? roAuth->PassWord : 
OUString());
                             long authAvail(0);
-                            auto const rc = 
curl_easy_getinfo(rSession.m_pCurl.get(),
-                                                              statusCode == 
SC_UNAUTHORIZED
-                                                                  ? 
CURLINFO_HTTPAUTH_AVAIL
-                                                                  : 
CURLINFO_PROXYAUTH_AVAIL,
-                                                              &authAvail);
+                            auto const rc
+                                = curl_easy_getinfo(rSession.m_pCurl.get(),
+                                                    statusCode != 
SC_PROXY_AUTHENTICATION_REQUIRED
+                                                        ? 
CURLINFO_HTTPAUTH_AVAIL
+                                                        : 
CURLINFO_PROXYAUTH_AVAIL,
+                                                    &authAvail);
                             assert(rc == CURLE_OK);
                             (void)rc;
+                            if (statusCode == SC_FORBIDDEN)
+                            { // SharePoint fallback: try Negotiate auth
+                                assert(authAvail == 0);
+                                // note: this must be a single value!
+                                // would need 2 iterations to try 
CURLAUTH_NTLM too
+                                authAvail = CURLAUTH_NEGOTIATE;
+                            }
                             // only allow SystemCredentials once - the
                             // PasswordContainer may have stored it in the
                             // Config (TrySystemCredentialsFirst or
@@ -1436,8 +1472,9 @@ auto CurlProcessor::ProcessRequest(
 
                             auto const ret = 
pEnv->m_xAuthListener->authenticate(
                                 oRealm ? *oRealm : "",
-                                statusCode == SC_UNAUTHORIZED ? 
rSession.m_URI.GetHost()
-                                                              : 
rSession.m_Proxy,
+                                statusCode != SC_PROXY_AUTHENTICATION_REQUIRED
+                                    ? rSession.m_URI.GetHost()
+                                    : rSession.m_Proxy,
                                 userName, passWord, isSystemCredSupported);
 
                             if (ret == 0)

Reply via email to