[GTK][WPE] Add API to allow applications to handle the HTTP authentication credential...
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Jun 2020 07:55:19 +0000 (07:55 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Jun 2020 07:55:19 +0000 (07:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=213177

Reviewed by Michael Catanzaro.

Source/WebKit:

Add API to disable the internal credential storage support when building with libsecret. And add new API to
WebKitAuthenticationRequest to allow applications to use their own credentials storage:

* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/NetworkSessionCreationParameters.cpp:
(WebKit::NetworkSessionCreationParameters::encode const):
(WebKit::NetworkSessionCreationParameters::decode):
* NetworkProcess/NetworkSessionCreationParameters.h:
* NetworkProcess/soup/NetworkDataTaskSoup.cpp:
(WebKit::NetworkDataTaskSoup::persistentCredentialStorageEnabled const):
(WebKit::NetworkDataTaskSoup::authenticate):
(WebKit::NetworkDataTaskSoup::continueAuthenticate):
(WebKit::NetworkDataTaskSoup::didGetHeaders):
* NetworkProcess/soup/NetworkDataTaskSoup.h:
* NetworkProcess/soup/NetworkProcessSoup.cpp:
(WebKit::NetworkProcess::setPersistentCredentialStorageEnabled):
* NetworkProcess/soup/NetworkSessionSoup.cpp:
(WebKit::NetworkSessionSoup::NetworkSessionSoup):
* NetworkProcess/soup/NetworkSessionSoup.h:
* UIProcess/API/glib/WebKitAuthenticationRequest.cpp:
(webkitAuthenticationRequestDispose):
(webkit_authentication_request_class_init):
(webkitAuthenticationRequestCreate):
(webkitAuthenticationRequestDidAuthenticate):
(webkitAuthenticationRequestGetProposedCredential):
(webkit_authentication_request_can_save_credentials):
(webkit_authentication_request_set_can_save_credentials):
(webkit_authentication_request_get_proposed_credential):
(webkit_authentication_request_set_proposed_credential):
(webkit_authentication_request_authenticate):
(webkit_authentication_request_cancel):
* UIProcess/API/glib/WebKitAuthenticationRequestPrivate.h:
* UIProcess/API/glib/WebKitWebView.cpp:
(webkitWebViewCompleteAuthenticationRequest):
(webkitWebViewLoadChanged):
(webkitWebViewLoadFailed):
(webkitWebViewLoadFailedWithTLSErrors):
(webkitWebViewHandleAuthenticationChallenge):
* UIProcess/API/glib/WebKitWebsiteDataManager.cpp:
(webkit_website_data_manager_set_persistent_credential_storage_enabled):
(webkit_website_data_manager_get_persistent_credential_storage_enabled):
* UIProcess/API/gtk/WebKitAuthenticationDialog.cpp:
(webkitAuthenticationDialogInitialize):
* UIProcess/API/gtk/WebKitAuthenticationRequest.h:
* UIProcess/API/gtk/WebKitWebsiteDataManager.h:
* UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
* UIProcess/API/wpe/WebKitAuthenticationRequest.h:
* UIProcess/API/wpe/WebKitWebsiteDataManager.h:
* UIProcess/API/wpe/docs/wpe-1.0-sections.txt:
* UIProcess/WebsiteData/WebsiteDataStore.h:
(WebKit::WebsiteDataStore::persistentCredentialStorageEnabled const):
* UIProcess/WebsiteData/soup/WebsiteDataStoreSoup.cpp:
(WebKit::WebsiteDataStore::platformSetNetworkParameters):
(WebKit::WebsiteDataStore::setPersistentCredentialStorageEnabled):
* UIProcess/soup/WebProcessPoolSoup.cpp:
(WebKit::WebProcessPool::platformInitializeNetworkProcess):

Tools:

Update the authentication tests to check the new API.

* TestWebKitAPI/Tests/WebKitGLib/TestAuthentication.cpp:
(testWebViewAuthenticationCancel):
(testWebViewAuthenticationLoadCancelled):
(testWebViewAuthenticationFailure):
(testWebViewAuthenticationNoCredential):
(testWebViewAuthenticationEphemeral):
(testWebViewAuthenticationStorage):
(testWebViewAuthenticationSuccess):
(testWebViewAuthenticationEmptyRealm):
(serverCallback):
(beforeAll):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@263444 268f45cc-cd09-0410-ab3c-d52691b4dbfc

26 files changed:
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/NetworkProcess/NetworkSessionCreationParameters.cpp
Source/WebKit/NetworkProcess/NetworkSessionCreationParameters.h
Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h
Source/WebKit/NetworkProcess/soup/NetworkProcessSoup.cpp
Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp
Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.h
Source/WebKit/UIProcess/API/glib/WebKitAuthenticationRequest.cpp
Source/WebKit/UIProcess/API/glib/WebKitAuthenticationRequestPrivate.h
Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp
Source/WebKit/UIProcess/API/glib/WebKitWebsiteDataManager.cpp
Source/WebKit/UIProcess/API/gtk/WebKitAuthenticationDialog.cpp
Source/WebKit/UIProcess/API/gtk/WebKitAuthenticationRequest.h
Source/WebKit/UIProcess/API/gtk/WebKitWebsiteDataManager.h
Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt
Source/WebKit/UIProcess/API/wpe/WebKitAuthenticationRequest.h
Source/WebKit/UIProcess/API/wpe/WebKitWebsiteDataManager.h
Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Source/WebKit/UIProcess/WebsiteData/soup/WebsiteDataStoreSoup.cpp
Source/WebKit/UIProcess/soup/WebProcessPoolSoup.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitGLib/TestAuthentication.cpp

index 7f8c1f7..41e4c68 100644 (file)
@@ -1,5 +1,70 @@
 2020-06-24  Carlos Garcia Campos  <cgarcia@igalia.com>
 
+        [GTK][WPE] Add API to allow applications to handle the HTTP authentication credential storage
+        https://bugs.webkit.org/show_bug.cgi?id=213177
+
+        Reviewed by Michael Catanzaro.
+
+        Add API to disable the internal credential storage support when building with libsecret. And add new API to
+        WebKitAuthenticationRequest to allow applications to use their own credentials storage:
+
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * NetworkProcess/NetworkSessionCreationParameters.cpp:
+        (WebKit::NetworkSessionCreationParameters::encode const):
+        (WebKit::NetworkSessionCreationParameters::decode):
+        * NetworkProcess/NetworkSessionCreationParameters.h:
+        * NetworkProcess/soup/NetworkDataTaskSoup.cpp:
+        (WebKit::NetworkDataTaskSoup::persistentCredentialStorageEnabled const):
+        (WebKit::NetworkDataTaskSoup::authenticate):
+        (WebKit::NetworkDataTaskSoup::continueAuthenticate):
+        (WebKit::NetworkDataTaskSoup::didGetHeaders):
+        * NetworkProcess/soup/NetworkDataTaskSoup.h:
+        * NetworkProcess/soup/NetworkProcessSoup.cpp:
+        (WebKit::NetworkProcess::setPersistentCredentialStorageEnabled):
+        * NetworkProcess/soup/NetworkSessionSoup.cpp:
+        (WebKit::NetworkSessionSoup::NetworkSessionSoup):
+        * NetworkProcess/soup/NetworkSessionSoup.h:
+        * UIProcess/API/glib/WebKitAuthenticationRequest.cpp:
+        (webkitAuthenticationRequestDispose):
+        (webkit_authentication_request_class_init):
+        (webkitAuthenticationRequestCreate):
+        (webkitAuthenticationRequestDidAuthenticate):
+        (webkitAuthenticationRequestGetProposedCredential):
+        (webkit_authentication_request_can_save_credentials):
+        (webkit_authentication_request_set_can_save_credentials):
+        (webkit_authentication_request_get_proposed_credential):
+        (webkit_authentication_request_set_proposed_credential):
+        (webkit_authentication_request_authenticate):
+        (webkit_authentication_request_cancel):
+        * UIProcess/API/glib/WebKitAuthenticationRequestPrivate.h:
+        * UIProcess/API/glib/WebKitWebView.cpp:
+        (webkitWebViewCompleteAuthenticationRequest):
+        (webkitWebViewLoadChanged):
+        (webkitWebViewLoadFailed):
+        (webkitWebViewLoadFailedWithTLSErrors):
+        (webkitWebViewHandleAuthenticationChallenge):
+        * UIProcess/API/glib/WebKitWebsiteDataManager.cpp:
+        (webkit_website_data_manager_set_persistent_credential_storage_enabled):
+        (webkit_website_data_manager_get_persistent_credential_storage_enabled):
+        * UIProcess/API/gtk/WebKitAuthenticationDialog.cpp:
+        (webkitAuthenticationDialogInitialize):
+        * UIProcess/API/gtk/WebKitAuthenticationRequest.h:
+        * UIProcess/API/gtk/WebKitWebsiteDataManager.h:
+        * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
+        * UIProcess/API/wpe/WebKitAuthenticationRequest.h:
+        * UIProcess/API/wpe/WebKitWebsiteDataManager.h:
+        * UIProcess/API/wpe/docs/wpe-1.0-sections.txt:
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+        (WebKit::WebsiteDataStore::persistentCredentialStorageEnabled const):
+        * UIProcess/WebsiteData/soup/WebsiteDataStoreSoup.cpp:
+        (WebKit::WebsiteDataStore::platformSetNetworkParameters):
+        (WebKit::WebsiteDataStore::setPersistentCredentialStorageEnabled):
+        * UIProcess/soup/WebProcessPoolSoup.cpp:
+        (WebKit::WebProcessPool::platformInitializeNetworkProcess):
+
+2020-06-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
         [GTK][WPE] Do not set the default configuration again when creating the WebsiteDataStore
         https://bugs.webkit.org/show_bug.cgi?id=213340
 
index 3f996a9..7fb9f7b 100644 (file)
@@ -438,6 +438,7 @@ private:
     void setIgnoreTLSErrors(bool);
     void userPreferredLanguagesChanged(const Vector<String>&);
     void setNetworkProxySettings(const WebCore::SoupNetworkProxySettings&);
+    void setPersistentCredentialStorageEnabled(PAL::SessionID, bool);
 #endif
 
 #if USE(CURL)
index 08f0706..d2c8628 100644 (file)
@@ -32,6 +32,7 @@ messages -> NetworkProcess LegacyReceiver {
     UserPreferredLanguagesChanged(Vector<String> languages)
     SetNetworkProxySettings(struct WebCore::SoupNetworkProxySettings settings)
     PrefetchDNS(String hostname)
+    SetPersistentCredentialStorageEnabled(PAL::SessionID sessionID, bool enabled)
 #endif
 
 #if USE(CURL)
index 3d5180a..3d83cd2 100644 (file)
@@ -60,6 +60,7 @@ void NetworkSessionCreationParameters::encode(IPC::Encoder& encoder) const
 #if USE(SOUP)
     encoder << cookiePersistentStoragePath;
     encoder << cookiePersistentStorageType;
+    encoder << persistentCredentialStorageEnabled;
 #endif
 #if USE(CURL)
     encoder << cookiePersistentStorageFile;
@@ -162,6 +163,11 @@ Optional<NetworkSessionCreationParameters> NetworkSessionCreationParameters::dec
     decoder >> cookiePersistentStorageType;
     if (!cookiePersistentStorageType)
         return WTF::nullopt;
+
+    Optional<bool> persistentCredentialStorageEnabled;
+    decoder >> persistentCredentialStorageEnabled;
+    if (!persistentCredentialStorageEnabled)
+        return WTF::nullopt;
 #endif
 
 #if USE(CURL)
@@ -272,6 +278,7 @@ Optional<NetworkSessionCreationParameters> NetworkSessionCreationParameters::dec
 #if USE(SOUP)
         , WTFMove(*cookiePersistentStoragePath)
         , WTFMove(*cookiePersistentStorageType)
+        , WTFMove(*persistentCredentialStorageEnabled)
 #endif
 #if USE(CURL)
         , WTFMove(*cookiePersistentStorageFile)
index 7d42aa4..f677455 100644 (file)
@@ -72,6 +72,7 @@ struct NetworkSessionCreationParameters {
 #if USE(SOUP)
     String cookiePersistentStoragePath;
     SoupCookiePersistentStorageType cookiePersistentStorageType { SoupCookiePersistentStorageType::Text };
+    bool persistentCredentialStorageEnabled { true };
 #endif
 #if USE(CURL)
     String cookiePersistentStorageFile;
index 888b268..66c02bc 100644 (file)
@@ -454,6 +454,11 @@ bool NetworkDataTaskSoup::tlsConnectionAcceptCertificate(GTlsCertificate* certif
     return false;
 }
 
+bool NetworkDataTaskSoup::persistentCredentialStorageEnabled() const
+{
+    return static_cast<NetworkSessionSoup&>(*m_session).persistentCredentialStorageEnabled();
+}
+
 void NetworkDataTaskSoup::applyAuthenticationToRequest(ResourceRequest& request)
 {
     if (m_user.isEmpty() && m_password.isEmpty())
@@ -524,7 +529,7 @@ void NetworkDataTaskSoup::authenticate(AuthenticationChallenge&& challenge)
     // of all request latency, versus a one-time latency for the small subset of requests that
     // use HTTP authentication. In the end, this doesn't matter much, because persistent credentials
     // will become session credentials after the first use.
-    if (m_storedCredentialsPolicy == StoredCredentialsPolicy::Use) {
+    if (m_storedCredentialsPolicy == StoredCredentialsPolicy::Use && persistentCredentialStorageEnabled()) {
         auto protectionSpace = challenge.protectionSpace();
         m_session->networkStorageSession()->getCredentialFromPersistentStorage(protectionSpace, m_cancellable.get(),
             [this, protectedThis = makeRef(*this), authChallenge = WTFMove(challenge)] (Credential&& credential) mutable {
@@ -563,7 +568,7 @@ void NetworkDataTaskSoup::continueAuthenticate(AuthenticationChallenge&& challen
                 if (credential.persistence() == CredentialPersistenceForSession || credential.persistence() == CredentialPersistencePermanent)
                     m_session->networkStorageSession()->credentialStorage().set(m_partition, credential, challenge.protectionSpace(), challenge.failureResponse().url());
 
-                if (credential.persistence() == CredentialPersistencePermanent) {
+                if (credential.persistence() == CredentialPersistencePermanent && persistentCredentialStorageEnabled()) {
                     m_protectionSpaceForPersistentStorage = challenge.protectionSpace();
                     m_credentialForPersistentStorage = credential;
                 }
@@ -875,7 +880,7 @@ void NetworkDataTaskSoup::didGetHeaders()
     // since we are waiting until we know that this authentication succeeded before actually storing.
     // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
     // incorrect credentials or polluting the keychain with invalid credentials.
-    if (!isAuthenticationFailureStatusCode(m_soupMessage->status_code) && m_soupMessage->status_code < 500) {
+    if (!isAuthenticationFailureStatusCode(m_soupMessage->status_code) && m_soupMessage->status_code < 500 && persistentCredentialStorageEnabled()) {
         m_session->networkStorageSession()->saveCredentialToPersistentStorage(m_protectionSpaceForPersistentStorage, m_credentialForPersistentStorage);
         m_protectionSpaceForPersistentStorage = ProtectionSpace();
         m_credentialForPersistentStorage = Credential();
index 74e31f3..1ca4507 100644 (file)
@@ -71,6 +71,7 @@ private:
     static gboolean tlsConnectionAcceptCertificateCallback(GTlsConnection*, GTlsCertificate*, GTlsCertificateFlags, NetworkDataTaskSoup*);
     bool tlsConnectionAcceptCertificate(GTlsCertificate*, GTlsCertificateFlags);
 
+    bool persistentCredentialStorageEnabled() const;
     void applyAuthenticationToRequest(WebCore::ResourceRequest&);
     static void authenticateCallback(SoupSession*, SoupMessage*, SoupAuth*, gboolean retrying, NetworkDataTaskSoup*);
     void authenticate(WebCore::AuthenticationChallenge&&);
index f927019..60fa556 100644 (file)
@@ -181,6 +181,12 @@ void NetworkProcess::setNetworkProxySettings(const SoupNetworkProxySettings& set
     });
 }
 
+void NetworkProcess::setPersistentCredentialStorageEnabled(PAL::SessionID sessionID, bool enabled)
+{
+    if (auto* session = networkSession(sessionID))
+        static_cast<NetworkSessionSoup&>(*session).setPersistentCredentialStorageEnabled(enabled);
+}
+
 void NetworkProcess::platformProcessDidTransitionToForeground()
 {
     notImplemented();
index 407361f..bd07baa 100644 (file)
@@ -42,6 +42,7 @@ using namespace WebCore;
 NetworkSessionSoup::NetworkSessionSoup(NetworkProcess& networkProcess, NetworkSessionCreationParameters&& parameters)
     : NetworkSession(networkProcess, parameters)
     , m_networkSession(makeUnique<SoupNetworkSession>(m_sessionID))
+    , m_persistentCredentialStorageEnabled(parameters.persistentCredentialStorageEnabled)
 {
     auto* storageSession = networkStorageSession();
     ASSERT(storageSession);
index 466b278..ebdac59 100644 (file)
@@ -54,11 +54,15 @@ public:
 
     void setCookiePersistentStorage(const String& storagePath, SoupCookiePersistentStorageType);
 
+    void setPersistentCredentialStorageEnabled(bool enabled) { m_persistentCredentialStorageEnabled = enabled; }
+    bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled; }
+
 private:
     std::unique_ptr<WebSocketTask> createWebSocketTask(NetworkSocketChannel&, const WebCore::ResourceRequest&, const String& protocol) final;
     void clearCredentials() final;
 
     std::unique_ptr<WebCore::SoupNetworkSession> m_networkSession;
+    bool m_persistentCredentialStorageEnabled { true };
 };
 
 } // namespace WebKit
index d89f307..60040ab 100644 (file)
@@ -56,6 +56,7 @@ using namespace WebCore;
  */
 
 enum {
+    AUTHENTICATED,
     CANCELLED,
 
     LAST_SIGNAL
@@ -64,9 +65,13 @@ enum {
 struct _WebKitAuthenticationRequestPrivate {
     RefPtr<AuthenticationChallengeProxy> authenticationChallenge;
     bool privateBrowsingEnabled;
+    bool persistentCredentialStorageEnabled;
     bool handledRequest;
     CString host;
     CString realm;
+    Optional<WebCore::Credential> proposedCredential;
+    Optional<WebCore::Credential> acceptedCredential;
+    Optional<bool> canSaveCredentials;
 };
 
 static guint signals[LAST_SIGNAL] = { 0, };
@@ -105,8 +110,7 @@ static void webkitAuthenticationRequestDispose(GObject* object)
     WebKitAuthenticationRequest* request = WEBKIT_AUTHENTICATION_REQUEST(object);
 
     // Make sure the request is always handled before finalizing.
-    if (!request->priv->handledRequest)
-        webkit_authentication_request_cancel(request);
+    webkit_authentication_request_cancel(request);
 
     G_OBJECT_CLASS(webkit_authentication_request_parent_class)->dispose(object);
 }
@@ -117,6 +121,27 @@ static void webkit_authentication_request_class_init(WebKitAuthenticationRequest
     objectClass->dispose = webkitAuthenticationRequestDispose;
 
     /**
+     * WebKitAuthenticationRequest::authenticated:
+     * @request: the #WebKitAuthenticationRequest
+     * @credential: the #WebKitCredential accepted
+     *
+     * This signal is emitted when the user authentication request succeeded.
+     * Applications handling their own credential storage should connect to
+     * this signal to save the credentials.
+     *
+     * Since: 2.30
+     */
+    signals[AUTHENTICATED] =
+        g_signal_new(
+            "authenticated",
+            G_TYPE_FROM_CLASS(objectClass),
+            G_SIGNAL_RUN_LAST,
+            0, 0, nullptr,
+            g_cclosure_marshal_generic,
+            G_TYPE_NONE, 1,
+            WEBKIT_TYPE_CREDENTIAL | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+    /**
      * WebKitAuthenticationRequest::cancelled:
      * @request: the #WebKitAuthenticationRequest
      *
@@ -135,11 +160,12 @@ static void webkit_authentication_request_class_init(WebKitAuthenticationRequest
             G_TYPE_NONE, 0);
 }
 
-WebKitAuthenticationRequest* webkitAuthenticationRequestCreate(AuthenticationChallengeProxy* authenticationChallenge, bool privateBrowsingEnabled)
+WebKitAuthenticationRequest* webkitAuthenticationRequestCreate(AuthenticationChallengeProxy* authenticationChallenge, bool privateBrowsingEnabled, bool persistentCredentialStorageEnabled)
 {
     WebKitAuthenticationRequest* request = WEBKIT_AUTHENTICATION_REQUEST(g_object_new(WEBKIT_TYPE_AUTHENTICATION_REQUEST, NULL));
     request->priv->authenticationChallenge = authenticationChallenge;
     request->priv->privateBrowsingEnabled = privateBrowsingEnabled;
+    request->priv->persistentCredentialStorageEnabled = persistentCredentialStorageEnabled;
     return request;
 }
 
@@ -148,14 +174,30 @@ AuthenticationChallengeProxy* webkitAuthenticationRequestGetAuthenticationChalle
     return request->priv->authenticationChallenge.get();
 }
 
+void webkitAuthenticationRequestDidAuthenticate(WebKitAuthenticationRequest* request)
+{
+    auto* credential = webkitCredentialCreate(request->priv->acceptedCredential.valueOr(WebCore::Credential()));
+    g_signal_emit(request, signals[AUTHENTICATED], 0, credential);
+    webkit_credential_free(credential);
+}
+
+const WebCore::Credential& webkitAuthenticationRequestGetProposedCredential(WebKitAuthenticationRequest* request)
+{
+    if (request->priv->proposedCredential)
+        return request->priv->proposedCredential.value();
+    return request->priv->authenticationChallenge->core().proposedCredential();
+}
+
 /**
  * webkit_authentication_request_can_save_credentials:
  * @request: a #WebKitAuthenticationRequest
  *
  * Determine whether the authentication method associated with this
  * #WebKitAuthenticationRequest should allow the storage of credentials.
- * This will return %FALSE if WebKit doesn't support credential storing
- * or if private browsing is enabled.
+ * This will return %FALSE if WebKit doesn't support credential storing,
+ * if private browsing is enabled, or if persistent credential storage has been
+ * disabled in #WebKitWebsiteDataManager, unless credentials saving has been
+ * explicitly enabled with webkit_authentication_request_set_can_save_credentials().
  *
  * Returns: %TRUE if WebKit can store credentials or %FALSE otherwise.
  *
@@ -165,14 +207,42 @@ gboolean webkit_authentication_request_can_save_credentials(WebKitAuthentication
 {
     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), FALSE);
 
+    if (request->priv->privateBrowsingEnabled)
+        return FALSE;
+
+    if (request->priv->canSaveCredentials)
+        return request->priv->canSaveCredentials.value();
+
 #if USE(LIBSECRET)
-    return !request->priv->privateBrowsingEnabled;
+    return request->priv->persistentCredentialStorageEnabled;
 #else
     return FALSE;
 #endif
 }
 
 /**
+ * webkit_authentication_request_set_can_save_credentials:
+ * @request: a #WebKitAuthenticationRequest
+ * @enabled: value to set
+ *
+ * Set whether the authentication method associated with @request
+ * should allow the storage of credentials.
+ * This should be used by applications handling their own credentials
+ * storage to indicate that it should be supported even when internal
+ * credential storage is disabled or unsupported.
+ * Note that storing of credentials will not be allowed on ephemeral
+ * sessions in any case.
+ *
+ * Since: 2.30
+ */
+void webkit_authentication_request_set_can_save_credentials(WebKitAuthenticationRequest* request, gboolean enabled)
+{
+    g_return_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request));
+
+    request->priv->canSaveCredentials = enabled;
+}
+
+/**
  * webkit_authentication_request_get_proposed_credential:
  * @request: a #WebKitAuthenticationRequest
  *
@@ -187,16 +257,42 @@ gboolean webkit_authentication_request_can_save_credentials(WebKitAuthentication
  */
 WebKitCredential* webkit_authentication_request_get_proposed_credential(WebKitAuthenticationRequest* request)
 {
-    g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), 0);
+    g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), nullptr);
 
-    const auto& credential = request->priv->authenticationChallenge->core().proposedCredential();
+    const auto& credential = webkitAuthenticationRequestGetProposedCredential(request);
     if (credential.isEmpty())
-        return 0;
+        return nullptr;
 
     return webkitCredentialCreate(credential);
 }
 
 /**
+ * webkit_authentication_request_set_proposed_credential:
+ * @request: a #WebKitAuthenticationRequest
+ * @credential: a #WebKitCredential, or %NULL
+ *
+ * Set the #WebKitCredential of the proposed authentication challenge that was
+ * stored from a previous session. This should only be used by applications handling
+ * their own credential storage. (When using the default WebKit credential storage,
+ * webkit_authentication_request_get_proposed_credential() already contains previously-stored
+ * credentials.)
+ * Passing a %NULL @credential will clear the proposed credential.
+ *
+ * Since: 2.30
+ */
+void webkit_authentication_request_set_proposed_credential(WebKitAuthenticationRequest* request, WebKitCredential* credential)
+{
+    g_return_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request));
+
+    if (!credential) {
+        request->priv->proposedCredential = WTF::nullopt;
+        return;
+    }
+
+    request->priv->proposedCredential = webkitCredentialGetCredential(credential);
+}
+
+/**
  * webkit_authentication_request_get_host:
  * @request: a #WebKitAuthenticationRequest
  *
@@ -316,8 +412,11 @@ void webkit_authentication_request_authenticate(WebKitAuthenticationRequest* req
 {
     g_return_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request));
 
-    request->priv->authenticationChallenge->listener().completeChallenge(WebKit::AuthenticationChallengeDisposition::UseCredential, credential ? webkitCredentialGetCredential(credential) : WebCore::Credential());
-
+    if (credential)
+        request->priv->acceptedCredential = webkitCredentialGetCredential(credential);
+    else
+        request->priv->acceptedCredential = WTF::nullopt;
+    request->priv->authenticationChallenge->listener().completeChallenge(WebKit::AuthenticationChallengeDisposition::UseCredential, request->priv->acceptedCredential.valueOr(WebCore::Credential()));
     request->priv->handledRequest = true;
 }
 
@@ -334,7 +433,12 @@ void webkit_authentication_request_cancel(WebKitAuthenticationRequest* request)
 {
     g_return_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request));
 
+    if (request->priv->handledRequest)
+        return;
+
     request->priv->authenticationChallenge->listener().completeChallenge(WebKit::AuthenticationChallengeDisposition::Cancel);
+    request->priv->acceptedCredential = WTF::nullopt;
+    request->priv->handledRequest = true;
 
     g_signal_emit(request, signals[CANCELLED], 0);
 }
index 0059a10..b20e50e 100644 (file)
@@ -21,6 +21,9 @@
 
 #include "AuthenticationChallengeProxy.h"
 #include "WebKitAuthenticationRequest.h"
+#include <WebCore/Credential.h>
 
-WebKitAuthenticationRequest* webkitAuthenticationRequestCreate(WebKit::AuthenticationChallengeProxy*, bool privateBrowsingEnabled);
+WebKitAuthenticationRequest* webkitAuthenticationRequestCreate(WebKit::AuthenticationChallengeProxy*, bool privateBrowsingEnabled, bool persistentCredentialStorageEnabled);
 WebKit::AuthenticationChallengeProxy* webkitAuthenticationRequestGetAuthenticationChallenge(WebKitAuthenticationRequest*);
+void webkitAuthenticationRequestDidAuthenticate(WebKitAuthenticationRequest*);
+const WebCore::Credential& webkitAuthenticationRequestGetProposedCredential(WebKitAuthenticationRequest*);
index 7b87c43..caf8efe 100644 (file)
@@ -2247,13 +2247,25 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
         WEBKIT_TYPE_USER_MESSAGE);
 }
 
-static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView)
+static void webkitWebViewCompleteAuthenticationRequest(WebKitWebView* webView)
 {
-    if (!webView->priv->authenticationRequest)
+    WebKitWebViewPrivate* priv = webView->priv;
+    if (!priv->authenticationRequest)
         return;
 
-    webkit_authentication_request_cancel(webView->priv->authenticationRequest.get());
-    webView->priv->authenticationRequest.clear();
+    if (priv->mainResource) {
+        if (auto* response = webkit_web_resource_get_response(priv->mainResource.get())) {
+            auto statusCode = webkit_uri_response_get_status_code(response);
+            if (statusCode != SOUP_STATUS_UNAUTHORIZED && statusCode != SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED && statusCode < 500) {
+                webkitAuthenticationRequestDidAuthenticate(priv->authenticationRequest.get());
+                priv->authenticationRequest = nullptr;
+                return;
+            }
+        }
+    }
+
+    webkit_authentication_request_cancel(priv->authenticationRequest.get());
+    priv->authenticationRequest = nullptr;
 }
 
 void webkitWebViewCreatePage(WebKitWebView* webView, Ref<API::PageConfiguration>&& configuration)
@@ -2301,7 +2313,7 @@ void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
         webkitWebViewCancelFaviconRequest(webView);
         webkitWebViewWatchForChangesInFavicon(webView);
 #endif
-        webkitWebViewCancelAuthenticationRequest(webView);
+        webkitWebViewCompleteAuthenticationRequest(webView);
         priv->loadingResourcesMap.clear();
         priv->mainResource = nullptr;
         webView->priv->isActiveURIChangeBlocked = false;
@@ -2323,7 +2335,7 @@ void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
         break;
     }
     case WEBKIT_LOAD_FINISHED:
-        webkitWebViewCancelAuthenticationRequest(webView);
+        webkitWebViewCompleteAuthenticationRequest(webView);
         break;
     default:
         break;
@@ -2334,7 +2346,7 @@ void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
 
 void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error)
 {
-    webkitWebViewCancelAuthenticationRequest(webView);
+    webkitWebViewCompleteAuthenticationRequest(webView);
 
     gboolean returnValue;
     g_signal_emit(webView, signals[LOAD_FAILED], 0, loadEvent, failingURI, error, &returnValue);
@@ -2343,7 +2355,7 @@ void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent,
 
 void webkitWebViewLoadFailedWithTLSErrors(WebKitWebView* webView, const char* failingURI, GError* error, GTlsCertificateFlags tlsErrors, GTlsCertificate* certificate)
 {
-    webkitWebViewCancelAuthenticationRequest(webView);
+    webkitWebViewCompleteAuthenticationRequest(webView);
 
     WebKitTLSErrorsPolicy tlsErrorsPolicy = webkit_web_context_get_tls_errors_policy(webView->priv->context.get());
     if (tlsErrorsPolicy == WEBKIT_TLS_ERRORS_POLICY_FAIL) {
@@ -2692,7 +2704,9 @@ void webkitWebViewSubmitFormRequest(WebKitWebView* webView, WebKitFormSubmission
 
 void webkitWebViewHandleAuthenticationChallenge(WebKitWebView* webView, AuthenticationChallengeProxy* authenticationChallenge)
 {
-    webView->priv->authenticationRequest = adoptGRef(webkitAuthenticationRequestCreate(authenticationChallenge, webView->priv->isEphemeral));
+    auto* websiteDataManager = webkit_web_view_get_website_data_manager(webView);
+    webView->priv->authenticationRequest = adoptGRef(webkitAuthenticationRequestCreate(authenticationChallenge,
+        webView->priv->isEphemeral, webkit_website_data_manager_get_persistent_credential_storage_enabled(websiteDataManager)));
     gboolean returnValue;
     g_signal_emit(webView, signals[AUTHENTICATE], 0, webView->priv->authenticationRequest.get(), &returnValue);
 }
index dcfd536..a1b68f3 100644 (file)
@@ -870,6 +870,42 @@ gboolean webkit_website_data_manager_get_itp_enabled(WebKitWebsiteDataManager* m
     return webkitWebsiteDataManagerGetDataStore(manager).resourceLoadStatisticsEnabled();
 }
 
+/**
+ * webkit_website_data_manager_set_persistent_credential_storage_enabled:
+ * @manager: a #WebKitWebsiteDataManager
+ * @enabled: value to set
+ *
+ * Enable or disable persistent credential storage. When enabled, which is the default for
+ * non-ephemeral sessions, the network process will try to read and write HTTP authentiacation
+ * credentials from persistent storage.
+ *
+ * Since: 2.30
+ */
+void webkit_website_data_manager_set_persistent_credential_storage_enabled(WebKitWebsiteDataManager* manager, gboolean enabled)
+{
+    g_return_if_fail(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager));
+
+    webkitWebsiteDataManagerGetDataStore(manager).setPersistentCredentialStorageEnabled(enabled);
+}
+
+/**
+ * webkit_website_data_manager_get_persistent_credential_storage_enabled:
+ * @manager: a #WebKitWebsiteDataManager
+ *
+ * Get whether persistent credential storage is enabled or not.
+ * See also webkit_website_data_manager_set_persistent_credential_storage_enabled().
+ *
+ * Returns: %TRUE if persistent credential storage is enabled, or %FALSE otherwise.
+ *
+ * Since: 2.30
+ */
+gboolean webkit_website_data_manager_get_persistent_credential_storage_enabled(WebKitWebsiteDataManager* manager)
+{
+    g_return_val_if_fail(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager), FALSE);
+
+    return webkitWebsiteDataManagerGetDataStore(manager).persistentCredentialStorageEnabled();
+}
+
 static OptionSet<WebsiteDataType> toWebsiteDataTypes(WebKitWebsiteDataTypes types)
 {
     OptionSet<WebsiteDataType> returnValue;
index 2c18c00..bfc4dc7 100644 (file)
@@ -226,7 +226,7 @@ static void webkitAuthenticationDialogInitialize(WebKitAuthenticationDialog* aut
     gtk_entry_set_visibility(GTK_ENTRY(priv->passwordEntry), FALSE);
     gtk_widget_set_visible(priv->rememberCheckButton, priv->credentialStorageMode != DisallowPersistentStorage && !realm.isEmpty());
 
-    const WebCore::Credential& credentialFromPersistentStorage = challenge.proposedCredential();
+    const auto& credentialFromPersistentStorage = webkitAuthenticationRequestGetProposedCredential(priv->request.get());
     if (!credentialFromPersistentStorage.isEmpty()) {
         gtk_entry_set_text(GTK_ENTRY(priv->loginEntry), credentialFromPersistentStorage.user().utf8().data());
         gtk_entry_set_text(GTK_ENTRY(priv->passwordEntry), credentialFromPersistentStorage.password().utf8().data());
index 59cc9f0..b311a45 100644 (file)
@@ -92,9 +92,17 @@ webkit_authentication_request_get_type                (void);
 WEBKIT_API gboolean
 webkit_authentication_request_can_save_credentials    (WebKitAuthenticationRequest *request);
 
+WEBKIT_API void
+webkit_authentication_request_set_can_save_credentials(WebKitAuthenticationRequest *request,
+                                                       gboolean                     enabled);
+
 WEBKIT_API WebKitCredential *
 webkit_authentication_request_get_proposed_credential (WebKitAuthenticationRequest *request);
 
+WEBKIT_API void
+webkit_authentication_request_set_proposed_credential (WebKitAuthenticationRequest *request,
+                                                       WebKitCredential            *credential);
+
 WEBKIT_API const gchar *
 webkit_authentication_request_get_host                (WebKitAuthenticationRequest *request);
 
index e3f6855..c7112c5 100644 (file)
@@ -113,6 +113,13 @@ WEBKIT_API gboolean
 webkit_website_data_manager_get_itp_enabled                           (WebKitWebsiteDataManager *manager);
 
 WEBKIT_API void
+webkit_website_data_manager_set_persistent_credential_storage_enabled (WebKitWebsiteDataManager *manager,
+                                                                       gboolean                  enabled);
+
+WEBKIT_API gboolean
+webkit_website_data_manager_get_persistent_credential_storage_enabled (WebKitWebsiteDataManager *manager);
+
+WEBKIT_API void
 webkit_website_data_manager_fetch                                     (WebKitWebsiteDataManager *manager,
                                                                        WebKitWebsiteDataTypes    types,
                                                                        GCancellable             *cancellable,
index 1c367ee..d4210a8 100644 (file)
@@ -345,10 +345,12 @@ WebKitAuthenticationScheme
 webkit_authentication_request_authenticate
 webkit_authentication_request_cancel
 webkit_authentication_request_can_save_credentials
+webkit_authentication_request_set_can_save_credentials
 webkit_authentication_request_get_host
 webkit_authentication_request_get_port
 webkit_authentication_request_is_retry
 webkit_authentication_request_get_proposed_credential
+webkit_authentication_request_set_proposed_credential
 webkit_authentication_request_get_realm
 webkit_authentication_request_get_scheme
 webkit_authentication_request_is_for_proxy
@@ -1467,6 +1469,8 @@ webkit_website_data_manager_get_dom_cache_directory
 webkit_website_data_manager_get_cookie_manager
 webkit_website_data_manager_set_itp_enabled
 webkit_website_data_manager_get_itp_enabled
+webkit_website_data_manager_set_persistent_credential_storage_enabled
+webkit_website_data_manager_get_persistent_credential_storage_enabled
 webkit_website_data_manager_fetch
 webkit_website_data_manager_fetch_finish
 webkit_website_data_manager_remove
index 98ea6fc..e514418 100644 (file)
@@ -91,9 +91,17 @@ webkit_authentication_request_get_type                (void);
 WEBKIT_API gboolean
 webkit_authentication_request_can_save_credentials    (WebKitAuthenticationRequest *request);
 
+WEBKIT_API void
+webkit_authentication_request_set_can_save_credentials(WebKitAuthenticationRequest *request,
+                                                       gboolean                     enabled);
+
 WEBKIT_API WebKitCredential *
 webkit_authentication_request_get_proposed_credential (WebKitAuthenticationRequest *request);
 
+WEBKIT_API void
+webkit_authentication_request_set_proposed_credential (WebKitAuthenticationRequest *request,
+                                                       WebKitCredential            *credential);
+
 WEBKIT_API const gchar *
 webkit_authentication_request_get_host                (WebKitAuthenticationRequest *request);
 
index 1750235..ae438fe 100644 (file)
@@ -113,6 +113,13 @@ WEBKIT_API gboolean
 webkit_website_data_manager_get_itp_enabled                           (WebKitWebsiteDataManager *manager);
 
 WEBKIT_API void
+webkit_website_data_manager_set_persistent_credential_storage_enabled (WebKitWebsiteDataManager *manager,
+                                                                       gboolean                  enabled);
+
+WEBKIT_API gboolean
+webkit_website_data_manager_get_persistent_credential_storage_enabled (WebKitWebsiteDataManager *manager);
+
+WEBKIT_API void
 webkit_website_data_manager_fetch                                     (WebKitWebsiteDataManager *manager,
                                                                        WebKitWebsiteDataTypes    types,
                                                                        GCancellable             *cancellable,
index c86dbc7..059207e 100644 (file)
@@ -348,10 +348,12 @@ WebKitAuthenticationScheme
 webkit_authentication_request_authenticate
 webkit_authentication_request_cancel
 webkit_authentication_request_can_save_credentials
+webkit_authentication_request_set_can_save_credentials
 webkit_authentication_request_get_host
 webkit_authentication_request_get_port
 webkit_authentication_request_is_retry
 webkit_authentication_request_get_proposed_credential
+webkit_authentication_request_set_proposed_credential
 webkit_authentication_request_get_realm
 webkit_authentication_request_get_scheme
 webkit_authentication_request_is_for_proxy
@@ -1401,6 +1403,8 @@ webkit_website_data_manager_get_dom_cache_directory
 webkit_website_data_manager_get_cookie_manager
 webkit_website_data_manager_set_itp_enabled
 webkit_website_data_manager_get_itp_enabled
+webkit_website_data_manager_set_persistent_credential_storage_enabled
+webkit_website_data_manager_get_persistent_credential_storage_enabled
 webkit_website_data_manager_fetch
 webkit_website_data_manager_fetch_finish
 webkit_website_data_manager_remove
index 713f5ed..e422adc 100644 (file)
@@ -242,6 +242,11 @@ public:
     const WebCore::CurlProxySettings& networkProxySettings() const { return m_proxySettings; }
 #endif
 
+#if USE(SOUP)
+    void setPersistentCredentialStorageEnabled(bool);
+    bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled && isPersistent(); }
+#endif
+
     static void allowWebsiteDataRecordsForAllOrigins();
 
 #if HAVE(SEC_KEY_PROXY)
@@ -368,6 +373,10 @@ private:
     WebCore::CurlProxySettings m_proxySettings;
 #endif
 
+#if USE(SOUP)
+    bool m_persistentCredentialStorageEnabled { true };
+#endif
+
     HashSet<WebCore::Cookie> m_pendingCookies;
     
     WeakHashSet<WebProcessProxy> m_processes;
index 489c3f2..12f9cd8 100644 (file)
@@ -27,6 +27,7 @@
 #include "config.h"
 #include "WebsiteDataStore.h"
 
+#include "NetworkProcessMessages.h"
 #include "WebCookieManagerProxy.h"
 #include "WebProcessPool.h"
 #include "WebsiteDataStoreParameters.h"
@@ -36,9 +37,23 @@ namespace WebKit {
 void WebsiteDataStore::platformSetNetworkParameters(WebsiteDataStoreParameters& parameters)
 {
     auto& networkSessionParameters = parameters.networkSessionParameters;
+    networkSessionParameters.persistentCredentialStorageEnabled = m_persistentCredentialStorageEnabled;
 
     if (auto* processPool = processPoolForCookieStorageOperations())
         processPool->supplement<WebCookieManagerProxy>()->getCookiePersistentStorage(m_sessionID, networkSessionParameters.cookiePersistentStoragePath, networkSessionParameters.cookiePersistentStorageType);
 }
 
+void WebsiteDataStore::setPersistentCredentialStorageEnabled(bool enabled)
+{
+    if (persistentCredentialStorageEnabled() == enabled)
+        return;
+
+    if (enabled && !isPersistent())
+        return;
+
+    m_persistentCredentialStorageEnabled = enabled;
+    for (auto& processPool : processPools())
+        processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetPersistentCredentialStorageEnabled(m_sessionID, m_persistentCredentialStorageEnabled));
 }
+
+} // namespace WebKit
index 59ee788..b6e566c 100644 (file)
@@ -39,6 +39,8 @@ void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationPara
 {
     NetworkSessionCreationParameters& defaultSessionParameters = parameters.defaultDataStoreParameters.networkSessionParameters;
     supplement<WebCookieManagerProxy>()->getCookiePersistentStorage(defaultSessionParameters.sessionID, defaultSessionParameters.cookiePersistentStoragePath, defaultSessionParameters.cookiePersistentStorageType);
+    if (m_websiteDataStore)
+        defaultSessionParameters.persistentCredentialStorageEnabled = m_websiteDataStore->persistentCredentialStorageEnabled();
 
     parameters.cookieAcceptPolicy = m_initialHTTPCookieAcceptPolicy;
     parameters.ignoreTLSErrors = m_ignoreTLSErrors;
index ef3bc91..ab0a98d 100644 (file)
@@ -1,3 +1,24 @@
+2020-06-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to allow applications to handle the HTTP authentication credential storage
+        https://bugs.webkit.org/show_bug.cgi?id=213177
+
+        Reviewed by Michael Catanzaro.
+
+        Update the authentication tests to check the new API.
+
+        * TestWebKitAPI/Tests/WebKitGLib/TestAuthentication.cpp:
+        (testWebViewAuthenticationCancel):
+        (testWebViewAuthenticationLoadCancelled):
+        (testWebViewAuthenticationFailure):
+        (testWebViewAuthenticationNoCredential):
+        (testWebViewAuthenticationEphemeral):
+        (testWebViewAuthenticationStorage):
+        (testWebViewAuthenticationSuccess):
+        (testWebViewAuthenticationEmptyRealm):
+        (serverCallback):
+        (beforeAll):
+
 2020-06-23  Alex Christensen  <achristensen@webkit.org>
 
         Make HTTP/3 experimental feature work on iOS and only create storage directory if enabled
index 5e859eb..5825286 100644 (file)
 
 static WebKitTestServer* kServer;
 
+static const char authTestUsername[] = "username";
+static const char authTestPassword[] = "password";
+static const char authExpectedSuccessTitle[] = "WebKit2Gtk+ Authentication test";
+static const char authExpectedFailureTitle[] = "401 Authorization Required";
+static const char authExpectedAuthorization[] = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="; // Base64 encoding of "username:password".
+static const char authSuccessHTMLString[] =
+    "<html>"
+    "<head><title>WebKit2Gtk+ Authentication test</title></head>"
+    "<body></body></html>";
+static const char authFailureHTMLString[] =
+    "<html>"
+    "<head><title>401 Authorization Required</title></head>"
+    "<body></body></html>";
+
 class AuthenticationTest: public LoadTrackingTest {
 public:
     MAKE_GLIB_TEST_FIXTURE(AuthenticationTest);
@@ -39,26 +53,39 @@ public:
     }
 
     static int authenticationRetries;
-    static bool authenticationCancelledReceived;
 
     void loadURI(const char* uri)
     {
         // Reset the retry count of the fake server when a page is loaded.
         authenticationRetries = 0;
-        authenticationCancelledReceived = false;
+        m_authenticationCancelledReceived = false;
         LoadTrackingTest::loadURI(uri);
     }
 
     static gboolean runAuthenticationCallback(WebKitWebView*, WebKitAuthenticationRequest* request, AuthenticationTest* test)
     {
+        g_signal_connect(request, "authenticated", G_CALLBACK(authenticationSucceededCallback), test);
         g_signal_connect(request, "cancelled", G_CALLBACK(authenticationCancelledCallback), test);
         test->runAuthentication(request);
         return TRUE;
     }
 
-    static void authenticationCancelledCallback(WebKitAuthenticationRequest*, AuthenticationTest*)
+    static void authenticationSucceededCallback(WebKitAuthenticationRequest*, WebKitCredential* credential, AuthenticationTest* test)
     {
-        authenticationCancelledReceived = true;
+        g_assert_nonnull(credential);
+        g_assert_cmpstr(webkit_credential_get_username(credential), ==, authTestUsername);
+        g_assert_cmpstr(webkit_credential_get_password(credential), ==, authTestPassword);
+        g_assert_cmpuint(webkit_credential_get_persistence(credential), ==, WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION);
+        g_assert_false(test->m_authenticationCancelledReceived);
+        g_assert_false(test->m_authenticationSucceededReceived);
+        test->m_authenticationSucceededReceived = true;
+    }
+
+    static void authenticationCancelledCallback(WebKitAuthenticationRequest*, AuthenticationTest* test)
+    {
+        g_assert_false(test->m_authenticationSucceededReceived);
+        g_assert_false(test->m_authenticationCancelledReceived);
+        test->m_authenticationCancelledReceived = true;
     }
 
     void runAuthentication(WebKitAuthenticationRequest* request)
@@ -74,8 +101,9 @@ public:
         return m_authenticationRequest.get();
     }
 
-private:
     GRefPtr<WebKitAuthenticationRequest> m_authenticationRequest;
+    bool m_authenticationSucceededReceived { false };
+    bool m_authenticationCancelledReceived { false };
 };
 
 class EphemeralAuthenticationTest : public AuthenticationTest {
@@ -94,21 +122,6 @@ public:
 };
 
 int AuthenticationTest::authenticationRetries = 0;
-bool AuthenticationTest::authenticationCancelledReceived = false;
-
-static const char authTestUsername[] = "username";
-static const char authTestPassword[] = "password";
-static const char authExpectedSuccessTitle[] = "WebKit2Gtk+ Authentication test";
-static const char authExpectedFailureTitle[] = "401 Authorization Required";
-static const char authExpectedAuthorization[] = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="; // Base64 encoding of "username:password".
-static const char authSuccessHTMLString[] =
-    "<html>"
-    "<head><title>WebKit2Gtk+ Authentication test</title></head>"
-    "<body></body></html>";
-static const char authFailureHTMLString[] =
-    "<html>"
-    "<head><title>401 Authorization Required</title></head>"
-    "<body></body></html>";
 
 static void testWebViewAuthenticationRequest(AuthenticationTest* test, gconstpointer)
 {
@@ -138,6 +151,8 @@ static void testWebViewAuthenticationCancel(AuthenticationTest* test, gconstpoin
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
 
     g_assert_error(test->m_error.get(), WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED);
+    g_assert_true(test->m_authenticationCancelledReceived);
+    g_assert_false(test->m_authenticationSucceededReceived);
 }
 
 static void testWebViewAuthenticationLoadCancelled(AuthenticationTest* test, gconstpointer)
@@ -147,7 +162,6 @@ static void testWebViewAuthenticationLoadCancelled(AuthenticationTest* test, gco
     webkit_web_view_stop_loading(test->m_webView);
     // Expect empty page.
     test->waitUntilLoadFinished();
-    g_assert_true(test->authenticationCancelledReceived);
 
     g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
     g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
@@ -155,6 +169,8 @@ static void testWebViewAuthenticationLoadCancelled(AuthenticationTest* test, gco
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
 
     g_assert_error(test->m_error.get(), WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED);
+    g_assert_true(test->m_authenticationCancelledReceived);
+    g_assert_false(test->m_authenticationSucceededReceived);
 }
 
 static void testWebViewAuthenticationFailure(AuthenticationTest* test, gconstpointer)
@@ -181,6 +197,8 @@ static void testWebViewAuthenticationFailure(AuthenticationTest* test, gconstpoi
     g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
     g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedFailureTitle);
+    g_assert_false(test->m_authenticationCancelledReceived);
+    g_assert_false(test->m_authenticationSucceededReceived);
 }
 
 static void testWebViewAuthenticationNoCredential(AuthenticationTest* test, gconstpointer)
@@ -197,6 +215,8 @@ static void testWebViewAuthenticationNoCredential(AuthenticationTest* test, gcon
     g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
     g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedFailureTitle);
+    g_assert_false(test->m_authenticationCancelledReceived);
+    g_assert_false(test->m_authenticationSucceededReceived);
 }
 
 static void testWebViewAuthenticationEphemeral(EphemeralAuthenticationTest* test, gconstpointer)
@@ -205,20 +225,57 @@ static void testWebViewAuthenticationEphemeral(EphemeralAuthenticationTest* test
     auto* request = test->waitForAuthenticationRequest();
     g_assert_null(webkit_authentication_request_get_proposed_credential(request));
     g_assert_false(webkit_authentication_request_can_save_credentials(request));
+    webkit_authentication_request_set_can_save_credentials(request, TRUE);
+    g_assert_false(webkit_authentication_request_can_save_credentials(request));
 }
 
-#if USE(LIBSECRET)
 static void testWebViewAuthenticationStorage(AuthenticationTest* test, gconstpointer)
 {
+    WebKitAuthenticationRequest* request = nullptr;
+#if USE(LIBSECRET)
     // If WebKit has been compiled with libsecret, and private browsing is disabled
     // then check that credentials can be saved.
     test->loadURI(kServer->getURIForPath("/auth-test.html").data());
-    auto* request = test->waitForAuthenticationRequest();
+    request = test->waitForAuthenticationRequest();
     g_assert_null(webkit_authentication_request_get_proposed_credential(request));
     g_assert_true(webkit_authentication_request_can_save_credentials(request));
-}
+    webkit_authentication_request_set_can_save_credentials(request, FALSE);
+    g_assert_false(webkit_authentication_request_can_save_credentials(request));
+    webkit_authentication_request_cancel(request);
+    test->waitUntilLoadFinished();
+    g_assert_true(test->m_authenticationCancelledReceived);
+    g_assert_false(test->m_authenticationSucceededReceived);
 #endif
 
+    auto* websiteDataManager = webkit_web_view_get_website_data_manager(test->m_webView);
+    g_assert_true(webkit_website_data_manager_get_persistent_credential_storage_enabled(websiteDataManager));
+    webkit_website_data_manager_set_persistent_credential_storage_enabled(websiteDataManager, FALSE);
+    g_assert_false(webkit_website_data_manager_get_persistent_credential_storage_enabled(websiteDataManager));
+
+    test->loadURI(kServer->getURIForPath("/auth-test.html").data());
+    request = test->waitForAuthenticationRequest();
+    g_assert_null(webkit_authentication_request_get_proposed_credential(request));
+    webkit_authentication_request_set_proposed_credential(request, nullptr);
+    g_assert_null(webkit_authentication_request_get_proposed_credential(request));
+    auto* credential = webkit_credential_new(authTestUsername, authTestPassword, WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION);
+    webkit_authentication_request_set_proposed_credential(request, credential);
+    auto* proposedCredential = webkit_authentication_request_get_proposed_credential(request);
+    g_assert_nonnull(proposedCredential);
+    g_assert_cmpstr(webkit_credential_get_username(credential), ==, webkit_credential_get_username(proposedCredential));
+    g_assert_cmpstr(webkit_credential_get_password(credential), ==, webkit_credential_get_password(proposedCredential));
+    g_assert_cmpuint(webkit_credential_get_persistence(credential), ==, webkit_credential_get_persistence(proposedCredential));
+    webkit_credential_free(proposedCredential);
+    g_assert_false(webkit_authentication_request_can_save_credentials(request));
+    webkit_authentication_request_set_can_save_credentials(request, TRUE);
+    g_assert_true(webkit_authentication_request_can_save_credentials(request));
+    webkit_authentication_request_authenticate(request, credential);
+    webkit_credential_free(credential);
+    test->waitUntilLoadFinished();
+    g_assert_false(test->m_authenticationCancelledReceived);
+    g_assert_true(test->m_authenticationSucceededReceived);
+    webkit_website_data_manager_set_persistent_credential_storage_enabled(websiteDataManager, TRUE);
+}
+
 static void testWebViewAuthenticationSuccess(AuthenticationTest* test, gconstpointer)
 {
     // Test correct authentication.
@@ -234,6 +291,8 @@ static void testWebViewAuthenticationSuccess(AuthenticationTest* test, gconstpoi
     g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
     g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedSuccessTitle);
+    g_assert_false(test->m_authenticationCancelledReceived);
+    g_assert_true(test->m_authenticationSucceededReceived);
 
     // Test loading the same (authorized) page again.
     test->loadURI(kServer->getURIForPath("/auth-test.html").data());
@@ -245,6 +304,8 @@ static void testWebViewAuthenticationSuccess(AuthenticationTest* test, gconstpoi
     g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
     g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedSuccessTitle);
+    g_assert_false(test->m_authenticationCancelledReceived);
+    g_assert_true(test->m_authenticationSucceededReceived);
 }
 
 static void testWebViewAuthenticationEmptyRealm(AuthenticationTest* test, gconstpointer)
@@ -261,6 +322,8 @@ static void testWebViewAuthenticationEmptyRealm(AuthenticationTest* test, gconst
     g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
     g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
     g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedSuccessTitle);
+    g_assert_false(test->m_authenticationCancelledReceived);
+    g_assert_true(test->m_authenticationSucceededReceived);
 }
 
 class Tunnel {
@@ -350,7 +413,7 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
             soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, authFailureHTMLString, strlen(authFailureHTMLString));
         } else {
             // Authentication not successful, display a "401 Authorization Required" page.
-            soup_message_set_status(message, SOUP_STATUS_OK);
+            soup_message_set_status(message, isProxy ? SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED : SOUP_STATUS_UNAUTHORIZED);
             soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, authFailureHTMLString, strlen(authFailureHTMLString));
         }
     } else
@@ -429,9 +492,7 @@ void beforeAll()
     AuthenticationTest::add("Authentication", "authentication-failure", testWebViewAuthenticationFailure);
     AuthenticationTest::add("Authentication", "authentication-no-credential", testWebViewAuthenticationNoCredential);
     EphemeralAuthenticationTest::add("Authentication", "authentication-ephemeral", testWebViewAuthenticationEphemeral);
-#if USE(LIBSECRET)
     AuthenticationTest::add("Authentication", "authentication-storage", testWebViewAuthenticationStorage);
-#endif
     AuthenticationTest::add("Authentication", "authentication-empty-realm", testWebViewAuthenticationEmptyRealm);
     ProxyAuthenticationTest::add("Authentication", "authentication-proxy", testWebViewAuthenticationProxy);
     ProxyAuthenticationTest::add("Authentication", "authentication-proxy-https", testWebViewAuthenticationProxyHTTPS);