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