Title: [187691] trunk/Source
Revision
187691
Author
[email protected]
Date
2015-07-31 16:56:00 -0700 (Fri, 31 Jul 2015)

Log Message

Source/WebCore:
Coalesce authentication credential requests
https://bugs.webkit.org/show_bug.cgi?id=128006
<rdar://problem/16839069>

Reviewed by Alexey Proskuryakov.

Export symbol for ProtectionSpace::compare() so it can be called from
WebKit2.

* platform/network/ProtectionSpaceBase.h:

Source/WebKit2:
Coalesce concurrent authentication challenges for the same ProtectionSpace
https://bugs.webkit.org/show_bug.cgi?id=147496
<rdar://problem/16839069>

Reviewed by Alexey Proskuryakov.

Coalesce concurrent authentication challenges for the same ProtectionSpace.
Ideally, this would be done in the network layer but short term, this will
make sure the user no longer gets repeating authentication dialogs for the
same protection space.

This gets rid of a long-standing bug in WebKit / Safari where visiting a
site using HTTP authentication would pop up one authentication dialog for
each subresource being loaded from the network (especially when the main
resource is loaded from the cache).

* Shared/Authentication/AuthenticationManager.cpp:
(WebKit::canCoalesceChallenge):
(WebKit::AuthenticationManager::addChallengeToChallengeMap):
(WebKit::AuthenticationManager::shouldCoalesceChallenge):
(WebKit::AuthenticationManager::coalesceChallengesMatching):
(WebKit::AuthenticationManager::didReceiveAuthenticationChallenge):
(WebKit::AuthenticationManager::useCredentialForChallenge):
(WebKit::AuthenticationManager::useCredentialForSingleChallenge):
(WebKit::AuthenticationManager::continueWithoutCredentialForChallenge):
(WebKit::AuthenticationManager::continueWithoutCredentialForSingleChallenge):
(WebKit::AuthenticationManager::cancelChallenge):
(WebKit::AuthenticationManager::cancelSingleChallenge):
(WebKit::AuthenticationManager::performDefaultHandling):
(WebKit::AuthenticationManager::performDefaultHandlingForSingleChallenge):
(WebKit::AuthenticationManager::rejectProtectionSpaceAndContinue):
(WebKit::AuthenticationManager::rejectProtectionSpaceAndContinueForSingleChallenge):
(WebKit::AuthenticationManager::AuthenticationManager): Deleted.
* Shared/Authentication/AuthenticationManager.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (187690 => 187691)


--- trunk/Source/WebCore/ChangeLog	2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebCore/ChangeLog	2015-07-31 23:56:00 UTC (rev 187691)
@@ -1,3 +1,16 @@
+2015-07-31  Chris Dumez  <[email protected]>
+
+        Coalesce authentication credential requests
+        https://bugs.webkit.org/show_bug.cgi?id=128006
+        <rdar://problem/16839069>
+
+        Reviewed by Alexey Proskuryakov.
+
+        Export symbol for ProtectionSpace::compare() so it can be called from
+        WebKit2.
+
+        * platform/network/ProtectionSpaceBase.h:
+
 2015-07-31  Eric Carlson  <[email protected]>
 
         [iOS] use a media-specific user gesture check

Modified: trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h (187690 => 187691)


--- trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h	2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h	2015-07-31 23:56:00 UTC (rev 187691)
@@ -72,7 +72,7 @@
 
     bool encodingRequiresPlatformData() const { return false; }
 
-    static bool compare(const ProtectionSpace& a, const ProtectionSpace& b);
+    WEBCORE_EXPORT static bool compare(const ProtectionSpace&, const ProtectionSpace&);
 
 protected:
     WEBCORE_EXPORT ProtectionSpaceBase();

Modified: trunk/Source/WebKit2/ChangeLog (187690 => 187691)


--- trunk/Source/WebKit2/ChangeLog	2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebKit2/ChangeLog	2015-07-31 23:56:00 UTC (rev 187691)
@@ -1,3 +1,40 @@
+2015-07-31  Chris Dumez  <[email protected]>
+
+        Coalesce concurrent authentication challenges for the same ProtectionSpace
+        https://bugs.webkit.org/show_bug.cgi?id=147496
+        <rdar://problem/16839069>
+
+        Reviewed by Alexey Proskuryakov.
+
+        Coalesce concurrent authentication challenges for the same ProtectionSpace.
+        Ideally, this would be done in the network layer but short term, this will
+        make sure the user no longer gets repeating authentication dialogs for the
+        same protection space.
+
+        This gets rid of a long-standing bug in WebKit / Safari where visiting a
+        site using HTTP authentication would pop up one authentication dialog for
+        each subresource being loaded from the network (especially when the main
+        resource is loaded from the cache).
+
+        * Shared/Authentication/AuthenticationManager.cpp:
+        (WebKit::canCoalesceChallenge):
+        (WebKit::AuthenticationManager::addChallengeToChallengeMap):
+        (WebKit::AuthenticationManager::shouldCoalesceChallenge):
+        (WebKit::AuthenticationManager::coalesceChallengesMatching):
+        (WebKit::AuthenticationManager::didReceiveAuthenticationChallenge):
+        (WebKit::AuthenticationManager::useCredentialForChallenge):
+        (WebKit::AuthenticationManager::useCredentialForSingleChallenge):
+        (WebKit::AuthenticationManager::continueWithoutCredentialForChallenge):
+        (WebKit::AuthenticationManager::continueWithoutCredentialForSingleChallenge):
+        (WebKit::AuthenticationManager::cancelChallenge):
+        (WebKit::AuthenticationManager::cancelSingleChallenge):
+        (WebKit::AuthenticationManager::performDefaultHandling):
+        (WebKit::AuthenticationManager::performDefaultHandlingForSingleChallenge):
+        (WebKit::AuthenticationManager::rejectProtectionSpaceAndContinue):
+        (WebKit::AuthenticationManager::rejectProtectionSpaceAndContinueForSingleChallenge):
+        (WebKit::AuthenticationManager::AuthenticationManager): Deleted.
+        * Shared/Authentication/AuthenticationManager.h:
+
 2015-07-31  Joseph Pecoraro  <[email protected]>
 
         Unreviewed parameter name typo fix.

Modified: trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.cpp (187690 => 187691)


--- trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.cpp	2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.cpp	2015-07-31 23:56:00 UTC (rev 187691)
@@ -53,6 +53,12 @@
     return ++uniqueAuthenticationChallengeID;
 }
 
+static bool canCoalesceChallenge(const WebCore::AuthenticationChallenge& challenge)
+{
+    // Do not coalesce server trust evaluation requests because ProtectionSpace comparison does not evaluate server trust (e.g. certificate).
+    return challenge.protectionSpace().authenticationScheme() != ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
+}
+
 const char* AuthenticationManager::supplementName()
 {
     return "AuthenticationManager";
@@ -64,7 +70,7 @@
     m_process->addMessageReceiver(Messages::AuthenticationManager::messageReceiverName(), *this);
 }
 
-uint64_t AuthenticationManager::establishIdentifierForChallenge(const WebCore::AuthenticationChallenge& authenticationChallenge)
+uint64_t AuthenticationManager::addChallengeToChallengeMap(const WebCore::AuthenticationChallenge& authenticationChallenge)
 {
     ASSERT(RunLoop::isMain());
 
@@ -73,12 +79,51 @@
     return challengeID;
 }
 
+bool AuthenticationManager::shouldCoalesceChallenge(uint64_t challengeID, const AuthenticationChallenge& challenge) const
+{
+    if (!canCoalesceChallenge(challenge))
+        return false;
+
+    auto end =  m_challenges.end();
+    for (auto it = m_challenges.begin(); it != end; ++it) {
+        if (it->key != challengeID && ProtectionSpace::compare(challenge.protectionSpace(), it->value.protectionSpace()))
+            return true;
+    }
+    return false;
+}
+
+Vector<uint64_t> AuthenticationManager::coalesceChallengesMatching(uint64_t challengeID) const
+{
+    AuthenticationChallenge challenge = m_challenges.get(challengeID);
+    ASSERT(!challenge.isNull());
+
+    Vector<uint64_t> challengesToCoalesce;
+    challengesToCoalesce.append(challengeID);
+
+    if (!canCoalesceChallenge(challenge))
+        return challengesToCoalesce;
+
+    auto end = m_challenges.end();
+    for (auto it = m_challenges.begin(); it != end; ++it) {
+        if (it->key != challengeID && ProtectionSpace::compare(challenge.protectionSpace(), it->value.protectionSpace()))
+            challengesToCoalesce.append(it->key);
+    }
+
+    return challengesToCoalesce;
+}
+
 void AuthenticationManager::didReceiveAuthenticationChallenge(WebFrame* frame, const AuthenticationChallenge& authenticationChallenge)
 {
     ASSERT(frame);
     ASSERT(frame->page());
+
+    uint64_t challengeID = addChallengeToChallengeMap(authenticationChallenge);
+
+    // Coalesce challenges in the same protection space.
+    if (shouldCoalesceChallenge(challengeID, authenticationChallenge))
+        return;
     
-    m_process->send(Messages::WebPageProxy::DidReceiveAuthenticationChallenge(frame->frameID(), authenticationChallenge, establishIdentifierForChallenge(authenticationChallenge)), frame->page()->pageID());
+    m_process->send(Messages::WebPageProxy::DidReceiveAuthenticationChallenge(frame->frameID(), authenticationChallenge, challengeID), frame->page()->pageID());
 }
 
 #if ENABLE(NETWORK_PROCESS)
@@ -86,14 +131,22 @@
 {
     ASSERT(pageID);
     ASSERT(frameID);
+
+    uint64_t challengeID = addChallengeToChallengeMap(authenticationChallenge);
+    if (shouldCoalesceChallenge(challengeID, authenticationChallenge))
+        return;
     
-    m_process->send(Messages::NetworkProcessProxy::DidReceiveAuthenticationChallenge(pageID, frameID, authenticationChallenge, establishIdentifierForChallenge(authenticationChallenge)));
+    m_process->send(Messages::NetworkProcessProxy::DidReceiveAuthenticationChallenge(pageID, frameID, authenticationChallenge, addChallengeToChallengeMap(authenticationChallenge)));
 }
 #endif
 
 void AuthenticationManager::didReceiveAuthenticationChallenge(Download* download, const AuthenticationChallenge& authenticationChallenge)
 {
-    download->send(Messages::DownloadProxy::DidReceiveAuthenticationChallenge(authenticationChallenge, establishIdentifierForChallenge(authenticationChallenge)));
+    uint64_t challengeID = addChallengeToChallengeMap(authenticationChallenge);
+    if (shouldCoalesceChallenge(challengeID, authenticationChallenge))
+        return;
+
+    download->send(Messages::DownloadProxy::DidReceiveAuthenticationChallenge(authenticationChallenge, addChallengeToChallengeMap(authenticationChallenge)));
 }
 
 // Currently, only Mac knows how to respond to authentication challenges with certificate info.
@@ -108,6 +161,12 @@
 {
     ASSERT(RunLoop::isMain());
 
+    for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+        useCredentialForSingleChallenge(coalescedChallengeID, credential, certificateInfo);
+}
+
+void AuthenticationManager::useCredentialForSingleChallenge(uint64_t challengeID, const Credential& credential, const CertificateInfo& certificateInfo)
+{
     AuthenticationChallenge challenge = m_challenges.take(challengeID);
     ASSERT(!challenge.isNull());
     
@@ -129,6 +188,12 @@
 {
     ASSERT(RunLoop::isMain());
 
+    for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+        continueWithoutCredentialForSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::continueWithoutCredentialForSingleChallenge(uint64_t challengeID)
+{
     AuthenticationChallenge challenge = m_challenges.take(challengeID);
     ASSERT(!challenge.isNull());
     AuthenticationClient* coreClient = challenge.authenticationClient();
@@ -146,6 +211,12 @@
 {
     ASSERT(RunLoop::isMain());
 
+    for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+        cancelSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::cancelSingleChallenge(uint64_t challengeID)
+{
     AuthenticationChallenge challenge = m_challenges.take(challengeID);
     ASSERT(!challenge.isNull());
     AuthenticationClient* coreClient = challenge.authenticationClient();
@@ -163,6 +234,12 @@
 {
     ASSERT(RunLoop::isMain());
 
+    for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+        performDefaultHandlingForSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::performDefaultHandlingForSingleChallenge(uint64_t challengeID)
+{
     AuthenticationChallenge challenge = m_challenges.take(challengeID);
     ASSERT(!challenge.isNull());
     AuthenticationClient* coreClient = challenge.authenticationClient();
@@ -180,6 +257,12 @@
 {
     ASSERT(RunLoop::isMain());
 
+    for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+        rejectProtectionSpaceAndContinueForSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::rejectProtectionSpaceAndContinueForSingleChallenge(uint64_t challengeID)
+{
     AuthenticationChallenge challenge = m_challenges.take(challengeID);
     ASSERT(!challenge.isNull());
     AuthenticationClient* coreClient = challenge.authenticationClient();

Modified: trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.h (187690 => 187691)


--- trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.h	2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.h	2015-07-31 23:56:00 UTC (rev 187691)
@@ -73,8 +73,17 @@
 
     bool tryUseCertificateInfoForChallenge(const WebCore::AuthenticationChallenge&, const WebCore::CertificateInfo&);
 
-    uint64_t establishIdentifierForChallenge(const WebCore::AuthenticationChallenge&);
+    uint64_t addChallengeToChallengeMap(const WebCore::AuthenticationChallenge&);
+    bool shouldCoalesceChallenge(uint64_t challengeID, const WebCore::AuthenticationChallenge&) const;
 
+    void useCredentialForSingleChallenge(uint64_t challengeID, const WebCore::Credential&, const WebCore::CertificateInfo&);
+    void continueWithoutCredentialForSingleChallenge(uint64_t challengeID);
+    void cancelSingleChallenge(uint64_t challengeID);
+    void performDefaultHandlingForSingleChallenge(uint64_t challengeID);
+    void rejectProtectionSpaceAndContinueForSingleChallenge(uint64_t challengeID);
+
+    Vector<uint64_t> coalesceChallengesMatching(uint64_t challengeID) const;
+
     ChildProcess* m_process;
 
     typedef HashMap<uint64_t, WebCore::AuthenticationChallenge> AuthenticationChallengeMap;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to