Clean up AuthenticationChallengeProxy
[WebKit-https.git] / Source / WebKit / UIProcess / API / glib / WebKitAuthenticationRequest.cpp
1 /*
2  * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "WebKitAuthenticationRequest.h"
22
23 #include "AuthenticationDecisionListener.h"
24 #include "WebCredential.h"
25 #include "WebKitAuthenticationRequestPrivate.h"
26 #include "WebKitCredentialPrivate.h"
27 #include "WebProtectionSpace.h"
28 #include <WebCore/AuthenticationChallenge.h>
29 #include <WebCore/ProtectionSpace.h>
30 #include <glib/gi18n-lib.h>
31 #include <wtf/glib/WTFGType.h>
32 #include <wtf/text/CString.h>
33
34 using namespace WebKit;
35 using namespace WebCore;
36
37 /**
38  * SECTION: WebKitAuthenticationRequest
39  * @Short_description: Represents an authentication request
40  * @Title: WebKitAuthenticationRequest
41  * @See_also: #WebKitWebView
42  *
43  * Whenever a client attempts to load a page protected by HTTP
44  * authentication, credentials will need to be provided to authorize access.
45  * To allow the client to decide how it wishes to handle authentication,
46  * WebKit will fire a #WebKitWebView::authenticate signal with a
47  * WebKitAuthenticationRequest object to provide client side
48  * authentication support. Credentials are exposed through the
49  * #WebKitCredential object.
50  *
51  * In case the client application does not wish
52  * to handle this signal WebKit will provide a default handler. To handle
53  * authentication asynchronously, simply increase the reference count of the
54  * WebKitAuthenticationRequest object.
55  */
56
57 enum {
58     CANCELLED,
59
60     LAST_SIGNAL
61 };
62
63 struct _WebKitAuthenticationRequestPrivate {
64     RefPtr<AuthenticationChallengeProxy> authenticationChallenge;
65     bool privateBrowsingEnabled;
66     bool handledRequest;
67     CString host;
68     CString realm;
69 };
70
71 static guint signals[LAST_SIGNAL] = { 0, };
72
73 WEBKIT_DEFINE_TYPE(WebKitAuthenticationRequest, webkit_authentication_request, G_TYPE_OBJECT)
74
75 static inline WebKitAuthenticationScheme toWebKitAuthenticationScheme(WebCore::ProtectionSpaceAuthenticationScheme coreScheme)
76 {
77     switch (coreScheme) {
78     case WebCore::ProtectionSpaceAuthenticationSchemeDefault:
79         return WEBKIT_AUTHENTICATION_SCHEME_DEFAULT;
80     case WebCore::ProtectionSpaceAuthenticationSchemeHTTPBasic:
81         return WEBKIT_AUTHENTICATION_SCHEME_HTTP_BASIC;
82     case WebCore::ProtectionSpaceAuthenticationSchemeHTTPDigest:
83         return WEBKIT_AUTHENTICATION_SCHEME_HTTP_DIGEST;
84     case WebCore::ProtectionSpaceAuthenticationSchemeHTMLForm:
85         return WEBKIT_AUTHENTICATION_SCHEME_HTML_FORM;
86     case WebCore::ProtectionSpaceAuthenticationSchemeNTLM:
87         return WEBKIT_AUTHENTICATION_SCHEME_NTLM;
88     case WebCore::ProtectionSpaceAuthenticationSchemeNegotiate:
89         return WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE;
90     case WebCore::ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
91         return WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED;
92     case WebCore::ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
93         return WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED;
94     case WebCore::ProtectionSpaceAuthenticationSchemeUnknown:
95         return WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN;
96     default:
97         ASSERT_NOT_REACHED();
98         return WEBKIT_AUTHENTICATION_SCHEME_DEFAULT;
99     }
100 }
101
102 static void webkitAuthenticationRequestDispose(GObject* object)
103 {
104     WebKitAuthenticationRequest* request = WEBKIT_AUTHENTICATION_REQUEST(object);
105
106     // Make sure the request is always handled before finalizing.
107     if (!request->priv->handledRequest)
108         webkit_authentication_request_cancel(request);
109
110     G_OBJECT_CLASS(webkit_authentication_request_parent_class)->dispose(object);
111 }
112
113 static void webkit_authentication_request_class_init(WebKitAuthenticationRequestClass* requestClass)
114 {
115     GObjectClass* objectClass = G_OBJECT_CLASS(requestClass);
116     objectClass->dispose = webkitAuthenticationRequestDispose;
117
118     /**
119      * WebKitAuthenticationRequest::cancelled:
120      * @request: the #WebKitAuthenticationRequest
121      *
122      * This signal is emitted when the user authentication request is
123      * cancelled. It allows the application to dismiss its authentication
124      * dialog in case of page load failure for example.
125      *
126      * Since: 2.2
127      */
128     signals[CANCELLED] =
129         g_signal_new("cancelled",
130             G_TYPE_FROM_CLASS(objectClass),
131             G_SIGNAL_RUN_LAST,
132             0, 0, 0,
133             g_cclosure_marshal_VOID__VOID,
134             G_TYPE_NONE, 0);
135 }
136
137 WebKitAuthenticationRequest* webkitAuthenticationRequestCreate(AuthenticationChallengeProxy* authenticationChallenge, bool privateBrowsingEnabled)
138 {
139     WebKitAuthenticationRequest* request = WEBKIT_AUTHENTICATION_REQUEST(g_object_new(WEBKIT_TYPE_AUTHENTICATION_REQUEST, NULL));
140     request->priv->authenticationChallenge = authenticationChallenge;
141     request->priv->privateBrowsingEnabled = privateBrowsingEnabled;
142     return request;
143 }
144
145 AuthenticationChallengeProxy* webkitAuthenticationRequestGetAuthenticationChallenge(WebKitAuthenticationRequest* request)
146 {
147     return request->priv->authenticationChallenge.get();
148 }
149
150 /**
151  * webkit_authentication_request_can_save_credentials:
152  * @request: a #WebKitAuthenticationRequest
153  *
154  * Determine whether the authentication method associated with this
155  * #WebKitAuthenticationRequest should allow the storage of credentials.
156  * This will return %FALSE if WebKit doesn't support credential storing
157  * or if private browsing is enabled.
158  *
159  * Returns: %TRUE if WebKit can store credentials or %FALSE otherwise.
160  *
161  * Since: 2.2
162  */
163 gboolean webkit_authentication_request_can_save_credentials(WebKitAuthenticationRequest* request)
164 {
165     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), FALSE);
166
167 #if USE(LIBSECRET)
168     return !request->priv->privateBrowsingEnabled;
169 #else
170     return FALSE;
171 #endif
172 }
173
174 /**
175  * webkit_authentication_request_get_proposed_credential:
176  * @request: a #WebKitAuthenticationRequest
177  *
178  * Get the #WebKitCredential of the proposed authentication challenge that was
179  * stored from a previous session. The client can use this directly for
180  * authentication or construct their own #WebKitCredential.
181  *
182  * Returns: (transfer full): A #WebKitCredential encapsulating credential details
183  * or %NULL if there is no stored credential.
184  *
185  * Since: 2.2
186  */
187 WebKitCredential* webkit_authentication_request_get_proposed_credential(WebKitAuthenticationRequest* request)
188 {
189     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), 0);
190
191     const auto& credential = request->priv->authenticationChallenge->core().proposedCredential();
192     if (credential.isEmpty())
193         return 0;
194
195     return webkitCredentialCreate(credential);
196 }
197
198 /**
199  * webkit_authentication_request_get_host:
200  * @request: a #WebKitAuthenticationRequest
201  *
202  * Get the host that this authentication challenge is applicable to.
203  *
204  * Returns: The host of @request.
205  *
206  * Since: 2.2
207  */
208 const gchar* webkit_authentication_request_get_host(WebKitAuthenticationRequest* request)
209 {
210     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), 0);
211
212     if (request->priv->host.isNull())
213         request->priv->host = request->priv->authenticationChallenge->core().protectionSpace().host().utf8();
214     return request->priv->host.data();
215 }
216
217 /**
218  * webkit_authentication_request_get_port:
219  * @request: a #WebKitAuthenticationRequest
220  *
221  * Get the port that this authentication challenge is applicable to.
222  *
223  * Returns: The port of @request.
224  *
225  * Since: 2.2
226  */
227 guint webkit_authentication_request_get_port(WebKitAuthenticationRequest* request)
228 {
229     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), 0);
230
231     return request->priv->authenticationChallenge->core().protectionSpace().port();
232 }
233
234 /**
235  * webkit_authentication_request_get_realm:
236  * @request: a #WebKitAuthenticationRequest
237  *
238  * Get the realm that this authentication challenge is applicable to.
239  *
240  * Returns: The realm of @request.
241  *
242  * Since: 2.2
243  */
244 const gchar* webkit_authentication_request_get_realm(WebKitAuthenticationRequest* request)
245 {
246     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), 0);
247
248     if (request->priv->realm.isNull())
249         request->priv->realm = request->priv->authenticationChallenge->core().protectionSpace().realm().utf8();
250     return request->priv->realm.data();
251 }
252
253 /**
254  * webkit_authentication_request_get_scheme:
255  * @request: a #WebKitAuthenticationRequest
256  *
257  * Get the authentication scheme of the authentication challenge.
258  *
259  * Returns: The #WebKitAuthenticationScheme of @request.
260  *
261  * Since: 2.2
262  */
263 WebKitAuthenticationScheme webkit_authentication_request_get_scheme(WebKitAuthenticationRequest* request)
264 {
265     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), WEBKIT_AUTHENTICATION_SCHEME_UNKNOWN);
266
267     return toWebKitAuthenticationScheme(request->priv->authenticationChallenge->core().protectionSpace().authenticationScheme());
268 }
269
270 /**
271  * webkit_authentication_request_is_for_proxy:
272  * @request: a #WebKitAuthenticationRequest
273  *
274  * Determine whether the authentication challenge is associated with a proxy server rather than an "origin" server.
275  *
276  * Returns: %TRUE if authentication is for a proxy or %FALSE otherwise.
277  *
278  * Since: 2.2
279  */
280 gboolean webkit_authentication_request_is_for_proxy(WebKitAuthenticationRequest* request)
281 {
282     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), FALSE);
283
284     return request->priv->authenticationChallenge->core().protectionSpace().isProxy();
285 }
286
287 /**
288  * webkit_authentication_request_is_retry:
289  * @request: a #WebKitAuthenticationRequest
290  *
291  * Determine whether this this is a first attempt or a retry for this authentication challenge.
292  *
293  * Returns: %TRUE if authentication attempt is a retry or %FALSE otherwise.
294  *
295  * Since: 2.2
296  */
297 gboolean webkit_authentication_request_is_retry(WebKitAuthenticationRequest* request)
298 {
299     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), 0);
300
301     return request->priv->authenticationChallenge->core().previousFailureCount() ? TRUE : FALSE;
302 }
303
304 /**
305  * webkit_authentication_request_authenticate:
306  * @request: a #WebKitAuthenticationRequest
307  * @credential: (transfer none) (allow-none): A #WebKitCredential, or %NULL
308  *
309  * Authenticate the #WebKitAuthenticationRequest using the #WebKitCredential
310  * supplied. To continue without credentials, pass %NULL as @credential.
311  *
312  * Since: 2.2
313  */
314 void webkit_authentication_request_authenticate(WebKitAuthenticationRequest* request, WebKitCredential* credential)
315 {
316     g_return_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request));
317
318     if (credential)
319         request->priv->authenticationChallenge->listener().useCredential(webkitCredentialGetCredential(credential));
320     else
321         request->priv->authenticationChallenge->listener().useCredential(std::nullopt);
322
323     request->priv->handledRequest = true;
324 }
325
326 /**
327  * webkit_authentication_request_cancel:
328  * @request: a #WebKitAuthenticationRequest
329  *
330  * Cancel the authentication challenge. This will also cancel the page loading and result in a
331  * #WebKitWebView::load-failed signal with a #WebKitNetworkError of type %WEBKIT_NETWORK_ERROR_CANCELLED being emitted.
332  *
333  * Since: 2.2
334  */
335 void webkit_authentication_request_cancel(WebKitAuthenticationRequest* request)
336 {
337     g_return_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request));
338
339     request->priv->authenticationChallenge->listener().cancel();
340
341     g_signal_emit(request, signals[CANCELLED], 0);
342 }