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