|
Packit |
4b6dd7 |
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
|
Packit |
4b6dd7 |
/*
|
|
Packit |
4b6dd7 |
* GData Client
|
|
Packit |
4b6dd7 |
* Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* GData Client is free software; you can redistribute it and/or
|
|
Packit |
4b6dd7 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
4b6dd7 |
* License as published by the Free Software Foundation; either
|
|
Packit |
4b6dd7 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* GData Client is distributed in the hope that it will be useful,
|
|
Packit |
4b6dd7 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4b6dd7 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
4b6dd7 |
* Lesser General Public License for more details.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
4b6dd7 |
* License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* SECTION:gdata-client-login-authorizer
|
|
Packit |
4b6dd7 |
* @short_description: GData ClientLogin authorization interface
|
|
Packit |
4b6dd7 |
* @stability: Stable
|
|
Packit |
4b6dd7 |
* @include: gdata/gdata-client-login-authorizer.h
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* #GDataClientLoginAuthorizer provides an implementation of the #GDataAuthorizer interface for authentication and authorization using the deprecated
|
|
Packit |
4b6dd7 |
* <ulink type="http" url="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html">ClientLogin</ulink> process.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* As noted, the ClientLogin process is being deprecated in favour of OAuth 2.0. This API is not (yet) deprecated, however. One of the main reasons
|
|
Packit |
4b6dd7 |
* for ClientLogin being deprecated is that it cannot support two-factor authentication as now available to Google Accounts. Any account which has
|
|
Packit |
4b6dd7 |
* two-factor authentication enabled has to use a service-specific one-time password instead if a client is authenticating with
|
|
Packit |
4b6dd7 |
* #GDataClientLoginAuthorizer. More documentation about this is
|
|
Packit |
4b6dd7 |
* <ulink type="http" url="http://www.google.com/support/accounts/bin/static.py?page=guide.cs&guide=1056283&topic=1056286">available online</ulink>.
|
|
Packit |
4b6dd7 |
* Note that newer services cannot be authenticated against using ClientLogin,
|
|
Packit |
4b6dd7 |
* and a #GDataOAuth2Authorizer must be used instead.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The ClientLogin process is a simple one whereby the user's Google Account username and password are sent over an HTTPS connection to the Google
|
|
Packit |
4b6dd7 |
* Account servers (when gdata_client_login_authorizer_authenticate() is called), which return an authorization token. This token is then attached to
|
|
Packit |
4b6dd7 |
* all future requests to the online service. A slight complication is that the Google Accounts service may return a CAPTCHA challenge instead of
|
|
Packit |
4b6dd7 |
* immediately returning an authorization token. In this case, the #GDataClientLoginAuthorizer::captcha-challenge signal will be emitted, and the
|
|
Packit |
4b6dd7 |
* user's response to the CAPTCHA should be returned by the handler.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* ClientLogin does not natively support authorization against multiple authorization domains concurrently with a single authorization token, so it
|
|
Packit |
4b6dd7 |
* has to be simulated by maintaining multiple authorization tokens if multiple authorization domains are used. This means that proportionally more
|
|
Packit |
4b6dd7 |
* network requests are made when gdata_client_login_authorizer_authenticate() is called, which will be proportionally slower. Handling of the
|
|
Packit |
4b6dd7 |
* multiple authorization tokens is otherwise transparent to the client.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Each authorization token is long lived, so reauthorization is rarely necessary with #GDataClientLoginAuthorizer. Consequently, refreshing
|
|
Packit |
4b6dd7 |
* authorization using gdata_authorizer_refresh_authorization() is not supported by #GDataClientLoginAuthorizer, and will immediately return %FALSE
|
|
Packit |
4b6dd7 |
* with no error set.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* <example>
|
|
Packit |
4b6dd7 |
* <title>Authenticating Asynchronously Using ClientLogin</title>
|
|
Packit |
4b6dd7 |
* <programlisting>
|
|
Packit |
4b6dd7 |
* GDataSomeService *service;
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer *authorizer;
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Create an authorizer and authenticate and authorize the service we're using, asynchronously. */
|
|
Packit |
4b6dd7 |
* authorizer = gdata_client_login_authorizer_new ("companyName-applicationName-versionID", GDATA_TYPE_SOME_SERVICE);
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_authenticate_async (authorizer, username, password, cancellable,
|
|
Packit |
4b6dd7 |
* (GAsyncReadyCallback) authenticate_cb, user_data);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Create a service object and link it with the authorizer */
|
|
Packit |
4b6dd7 |
* service = gdata_some_service_new (GDATA_AUTHORIZER (authorizer));
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* static void
|
|
Packit |
4b6dd7 |
* authenticate_cb (GDataClientLoginAuthorizer *authorizer, GAsyncResult *async_result, gpointer user_data)
|
|
Packit |
4b6dd7 |
* {
|
|
Packit |
4b6dd7 |
* GError *error = NULL;
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* if (gdata_client_login_authorizer_authenticate_finish (authorizer, async_result, &error) == FALSE) {
|
|
Packit |
4b6dd7 |
* /* Notify the user of all errors except cancellation errors */
|
|
Packit |
4b6dd7 |
* if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
|
Packit |
4b6dd7 |
* g_error ("Authentication failed: %s", error->message);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
* g_error_free (error);
|
|
Packit |
4b6dd7 |
* return;
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* (The client is now authenticated and authorized against the service.
|
|
Packit |
4b6dd7 |
* * It can now proceed to execute queries on the service object which require the user to be authenticated.) */
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_object_unref (service);
|
|
Packit |
4b6dd7 |
* g_object_unref (authorizer);
|
|
Packit |
4b6dd7 |
* </programlisting>
|
|
Packit |
4b6dd7 |
* </example>
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#include <config.h>
|
|
Packit |
4b6dd7 |
#include <glib.h>
|
|
Packit |
4b6dd7 |
#include <glib/gi18n-lib.h>
|
|
Packit |
4b6dd7 |
#include <string.h>
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#include "gdata-service.h"
|
|
Packit |
4b6dd7 |
#include "gdata-private.h"
|
|
Packit |
4b6dd7 |
#include "gdata-marshal.h"
|
|
Packit |
4b6dd7 |
#include "gdata-client-login-authorizer.h"
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* The default e-mail domain to use for usernames */
|
|
Packit |
4b6dd7 |
#define EMAIL_DOMAIN "gmail.com"
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
GQuark
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_error_quark (void)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
return g_quark_from_static_string ("gdata-client-login-authorizer-error-quark");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void authorizer_init (GDataAuthorizerInterface *iface);
|
|
Packit |
4b6dd7 |
static void dispose (GObject *object);
|
|
Packit |
4b6dd7 |
static void finalize (GObject *object);
|
|
Packit |
4b6dd7 |
static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
|
|
Packit |
4b6dd7 |
static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message);
|
|
Packit |
4b6dd7 |
static gboolean is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void notify_proxy_uri_cb (GObject *gobject, GParamSpec *pspec, GDataClientLoginAuthorizer *self);
|
|
Packit |
4b6dd7 |
static void notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static SoupURI *_get_proxy_uri (GDataClientLoginAuthorizer *self);
|
|
Packit |
4b6dd7 |
static void _set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
struct _GDataClientLoginAuthorizerPrivate {
|
|
Packit |
4b6dd7 |
SoupSession *session;
|
|
Packit |
4b6dd7 |
SoupURI *proxy_uri; /* cached version only set if gdata_client_login_authorizer_get_proxy_uri() is called */
|
|
Packit |
4b6dd7 |
GProxyResolver *proxy_resolver;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gchar *client_id;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Mutex for username, password and auth_tokens. It has to be recursive as the top-level authentication functions need to hold a lock on
|
|
Packit |
4b6dd7 |
* auth_tokens while looping over it, but lower-level functions also need to modify auth_tokens to add the auth_tokens themselves once they're
|
|
Packit |
4b6dd7 |
* returned by the online service. */
|
|
Packit |
4b6dd7 |
GRecMutex mutex;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gchar *username;
|
|
Packit |
4b6dd7 |
GDataSecureString password; /* must be allocated by _gdata_service_secure_strdup() */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Mapping from GDataAuthorizationDomain to string? auth_token; auth_token is NULL for domains which aren't authorised at the moment */
|
|
Packit |
4b6dd7 |
GHashTable *auth_tokens;
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
enum {
|
|
Packit |
4b6dd7 |
PROP_CLIENT_ID = 1,
|
|
Packit |
4b6dd7 |
PROP_USERNAME,
|
|
Packit |
4b6dd7 |
PROP_PASSWORD,
|
|
Packit |
4b6dd7 |
PROP_PROXY_URI,
|
|
Packit |
4b6dd7 |
PROP_TIMEOUT,
|
|
Packit |
4b6dd7 |
PROP_PROXY_RESOLVER,
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
enum {
|
|
Packit |
4b6dd7 |
SIGNAL_CAPTCHA_CHALLENGE,
|
|
Packit |
4b6dd7 |
LAST_SIGNAL
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static guint authorizer_signals[LAST_SIGNAL] = { 0, };
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
G_DEFINE_TYPE_WITH_CODE (GDataClientLoginAuthorizer, gdata_client_login_authorizer, G_TYPE_OBJECT,
|
|
Packit |
4b6dd7 |
G_IMPLEMENT_INTERFACE (GDATA_TYPE_AUTHORIZER, authorizer_init))
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_class_init (GDataClientLoginAuthorizerClass *klass)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_type_class_add_private (klass, sizeof (GDataClientLoginAuthorizerPrivate));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gobject_class->get_property = get_property;
|
|
Packit |
4b6dd7 |
gobject_class->set_property = set_property;
|
|
Packit |
4b6dd7 |
gobject_class->dispose = dispose;
|
|
Packit |
4b6dd7 |
gobject_class->finalize = finalize;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer:client-id:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* A client ID for your application (see the
|
|
Packit |
4b6dd7 |
* <ulink url="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Request" type="http">reference documentation</ulink>).
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* It is recommended that the ID is of the form <literal><replaceable>company name</replaceable>-<replaceable>application name</replaceable>-
|
|
Packit |
4b6dd7 |
* <replaceable>version ID</replaceable></literal>.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_CLIENT_ID,
|
|
Packit |
4b6dd7 |
g_param_spec_string ("client-id",
|
|
Packit |
4b6dd7 |
"Client ID", "A client ID for your application.",
|
|
Packit |
4b6dd7 |
NULL,
|
|
Packit |
4b6dd7 |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer:username:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The user's Google username for authentication. This will always be a full e-mail address.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This will only be set after authentication using gdata_client_login_authorizer_authenticate() is completed successfully. It will
|
|
Packit |
4b6dd7 |
* then be set to the username passed to gdata_client_login_authorizer_authenticate(), and a #GObject::notify signal will be emitted. If
|
|
Packit |
4b6dd7 |
* authentication fails, it will be set to %NULL.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_USERNAME,
|
|
Packit |
4b6dd7 |
g_param_spec_string ("username",
|
|
Packit |
4b6dd7 |
"Username", "The user's Google username for authentication.",
|
|
Packit |
4b6dd7 |
NULL,
|
|
Packit |
4b6dd7 |
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer:password:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The user's account password for authentication.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This will only be set after authentication using gdata_client_login_authorizer_authenticate() is completed successfully. It will
|
|
Packit |
4b6dd7 |
* then be set to the password passed to gdata_client_login_authorizer_authenticate(), and a #GObject::notify signal will be emitted. If
|
|
Packit |
4b6dd7 |
* authentication fails, it will be set to %NULL.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If libgdata is compiled with libgcr support, the password will be stored in non-pageable memory. However, if it is retrieved
|
|
Packit |
4b6dd7 |
* using g_object_get() (or related functions) it will be copied to non-pageable memory and could end up being written to disk. Accessing
|
|
Packit |
4b6dd7 |
* the password using gdata_client_login_authorizer_get_password() will not perform any copies, and so maintains privacy.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_PASSWORD,
|
|
Packit |
4b6dd7 |
g_param_spec_string ("password",
|
|
Packit |
4b6dd7 |
"Password", "The user's account password for authentication.",
|
|
Packit |
4b6dd7 |
NULL,
|
|
Packit |
4b6dd7 |
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer:proxy-uri:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The proxy URI used internally for all network requests.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
* Deprecated: 0.15.0: Use #GDataClientLoginAuthorizer:proxy-resolver instead, which gives more flexibility over the proxy used.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_PROXY_URI,
|
|
Packit |
4b6dd7 |
g_param_spec_boxed ("proxy-uri",
|
|
Packit |
4b6dd7 |
"Proxy URI", "The proxy URI used internally for all network requests.",
|
|
Packit |
4b6dd7 |
SOUP_TYPE_URI,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer:timeout:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* A timeout, in seconds, for network operations. If the timeout is exceeded, the operation will be cancelled and
|
|
Packit |
4b6dd7 |
* %GDATA_SERVICE_ERROR_NETWORK_ERROR will be returned.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If the timeout is 0 , operations will never time out.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_TIMEOUT,
|
|
Packit |
4b6dd7 |
g_param_spec_uint ("timeout",
|
|
Packit |
4b6dd7 |
"Timeout", "A timeout, in seconds, for network operations.",
|
|
Packit |
4b6dd7 |
0, G_MAXUINT, 0,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer:proxy-resolver:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The #GProxyResolver used to determine a proxy URI. Setting this will clear the #GDataClientLoginAuthorizer:proxy-uri property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.15.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
|
|
Packit |
4b6dd7 |
g_param_spec_object ("proxy-resolver",
|
|
Packit |
4b6dd7 |
"Proxy Resolver", "A GProxyResolver used to determine a proxy URI.",
|
|
Packit |
4b6dd7 |
G_TYPE_PROXY_RESOLVER,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataClientLoginAuthorizer::captcha-challenge:
|
|
Packit |
4b6dd7 |
* @authorizer: the #GDataClientLoginAuthorizer which received the challenge
|
|
Packit |
4b6dd7 |
* @uri: the URI of the CAPTCHA image to be used
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The #GDataClientLoginAuthorizer::captcha-challenge signal is emitted during the authentication process if the authorizer requires a CAPTCHA
|
|
Packit |
4b6dd7 |
* to be completed. The URI of a CAPTCHA image is given, and the program should display this to the user, and return their response (the text
|
|
Packit |
4b6dd7 |
* displayed in the image). There is no timeout imposed by the library for the response.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: a newly allocated string containing the text in the CAPTCHA image
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
authorizer_signals[SIGNAL_CAPTCHA_CHALLENGE] = g_signal_new ("captcha-challenge",
|
|
Packit |
4b6dd7 |
G_TYPE_FROM_CLASS (klass),
|
|
Packit |
4b6dd7 |
G_SIGNAL_RUN_LAST,
|
|
Packit |
4b6dd7 |
0, NULL, NULL,
|
|
Packit |
4b6dd7 |
gdata_marshal_STRING__OBJECT_STRING,
|
|
Packit |
4b6dd7 |
G_TYPE_STRING, 1, G_TYPE_STRING);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
authorizer_init (GDataAuthorizerInterface *iface)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
iface->process_request = process_request;
|
|
Packit |
4b6dd7 |
iface->is_authorized_for_domain = is_authorized_for_domain;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_init (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER, GDataClientLoginAuthorizerPrivate);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set up the authentication mutex */
|
|
Packit |
4b6dd7 |
g_rec_mutex_init (&(self->priv->mutex));
|
|
Packit |
4b6dd7 |
self->priv->auth_tokens = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) _gdata_service_secure_strfree);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set up the session */
|
|
Packit |
4b6dd7 |
self->priv->session = _gdata_service_build_session ();
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Proxy the SoupSession's proxy-uri and timeout properties */
|
|
Packit |
4b6dd7 |
g_signal_connect (self->priv->session, "notify::proxy-uri", (GCallback) notify_proxy_uri_cb, self);
|
|
Packit |
4b6dd7 |
g_signal_connect (self->priv->session, "notify::timeout", (GCallback) notify_timeout_cb, self);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Keep our GProxyResolver synchronized with SoupSession's. */
|
|
Packit |
4b6dd7 |
g_object_bind_property (self->priv->session, "proxy-resolver", self, "proxy-resolver", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
dispose (GObject *object)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->session != NULL) {
|
|
Packit |
4b6dd7 |
g_object_unref (priv->session);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
priv->session = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_clear_object (&priv->proxy_resolver);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Chain up to the parent class */
|
|
Packit |
4b6dd7 |
G_OBJECT_CLASS (gdata_client_login_authorizer_parent_class)->dispose (object);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
finalize (GObject *object)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (priv->username);
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (priv->password);
|
|
Packit |
4b6dd7 |
g_free (priv->client_id);
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (priv->auth_tokens);
|
|
Packit |
4b6dd7 |
g_rec_mutex_clear (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->proxy_uri != NULL) {
|
|
Packit |
4b6dd7 |
soup_uri_free (priv->proxy_uri);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Chain up to the parent class */
|
|
Packit |
4b6dd7 |
G_OBJECT_CLASS (gdata_client_login_authorizer_parent_class)->finalize (object);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
switch (property_id) {
|
|
Packit |
4b6dd7 |
case PROP_CLIENT_ID:
|
|
Packit |
4b6dd7 |
g_value_set_string (value, priv->client_id);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_USERNAME:
|
|
Packit |
4b6dd7 |
g_rec_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
g_value_set_string (value, priv->username);
|
|
Packit |
4b6dd7 |
g_rec_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PASSWORD:
|
|
Packit |
4b6dd7 |
/* NOTE: This takes a pageable copy of non-pageable memory and thus could result in the password hitting disk. */
|
|
Packit |
4b6dd7 |
g_rec_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
g_value_set_string (value, priv->password);
|
|
Packit |
4b6dd7 |
g_rec_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_URI:
|
|
Packit |
4b6dd7 |
g_value_set_boxed (value, _get_proxy_uri (GDATA_CLIENT_LOGIN_AUTHORIZER (object)));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_TIMEOUT:
|
|
Packit |
4b6dd7 |
g_value_set_uint (value, gdata_client_login_authorizer_get_timeout (GDATA_CLIENT_LOGIN_AUTHORIZER (object)));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_RESOLVER:
|
|
Packit |
4b6dd7 |
g_value_set_object (value, gdata_client_login_authorizer_get_proxy_resolver (GDATA_CLIENT_LOGIN_AUTHORIZER (object)));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We don't have any other property... */
|
|
Packit |
4b6dd7 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
switch (property_id) {
|
|
Packit |
4b6dd7 |
case PROP_CLIENT_ID:
|
|
Packit |
4b6dd7 |
priv->client_id = g_value_dup_string (value);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_URI:
|
|
Packit |
4b6dd7 |
_set_proxy_uri (GDATA_CLIENT_LOGIN_AUTHORIZER (object), g_value_get_boxed (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_TIMEOUT:
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_set_timeout (GDATA_CLIENT_LOGIN_AUTHORIZER (object), g_value_get_uint (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_RESOLVER:
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_set_proxy_resolver (GDATA_CLIENT_LOGIN_AUTHORIZER (object), g_value_get_object (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We don't have any other property... */
|
|
Packit |
4b6dd7 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataConstSecureString auth_token; /* privacy sensitive */
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (self)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* If the domain's NULL, return immediately */
|
|
Packit |
4b6dd7 |
if (domain == NULL) {
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set the authorisation header */
|
|
Packit |
4b6dd7 |
g_rec_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
auth_token = (GDataConstSecureString) g_hash_table_lookup (priv->auth_tokens, domain);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (auth_token != NULL) {
|
|
Packit |
4b6dd7 |
/* Ensure that we're using HTTPS: if not, we shouldn't set the Authorization header or we could be revealing the auth token to
|
|
Packit |
4b6dd7 |
* anyone snooping the connection, which would give them the same rights as us on the user's data. Generally a bad thing to happen. */
|
|
Packit |
4b6dd7 |
if (soup_message_get_uri (message)->scheme != SOUP_URI_SCHEME_HTTPS) {
|
|
Packit |
4b6dd7 |
g_warning ("Not authorizing a non-HTTPS message with the user's ClientLogin auth token as the connection isn't secure.");
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
/* Ideally, authorisation_header would be allocated in non-pageable memory. However, it's copied by
|
|
Packit |
4b6dd7 |
* soup_message_headers_replace() immediately anyway, so there's not much point. However, we do ensure we zero it out before
|
|
Packit |
4b6dd7 |
* freeing. */
|
|
Packit |
4b6dd7 |
gchar *authorisation_header = g_strdup_printf ("GoogleLogin auth=%s", auth_token);
|
|
Packit |
4b6dd7 |
soup_message_headers_replace (message->request_headers, "Authorization", authorisation_header);
|
|
Packit |
4b6dd7 |
memset (authorisation_header, 0, strlen (authorisation_header));
|
|
Packit |
4b6dd7 |
g_free (authorisation_header);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_rec_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static gboolean
|
|
Packit |
4b6dd7 |
is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (self)->priv;
|
|
Packit |
4b6dd7 |
gpointer result;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_rec_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
result = g_hash_table_lookup (priv->auth_tokens, domain);
|
|
Packit |
4b6dd7 |
g_rec_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return (result != NULL) ? TRUE : FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_new:
|
|
Packit |
4b6dd7 |
* @client_id: your application's client ID
|
|
Packit |
4b6dd7 |
* @service_type: the #GType of a #GDataService subclass which the #GDataClientLoginAuthorizer will be used with
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Creates a new #GDataClientLoginAuthorizer. The @client_id must be unique for your application, and as registered with Google.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The #GDataAuthorizationDomains for the given @service_type (i.e. as returned by gdata_service_get_authorization_domains()) are the ones the
|
|
Packit |
4b6dd7 |
* user will be logged in to using the provided username and password when gdata_client_login_authorizer_authenticate() is called. Note that the same
|
|
Packit |
4b6dd7 |
* username and password will be used for all domains.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): a new #GDataClientLoginAuthorizer, or %NULL; unref with g_object_unref()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizer *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_new (const gchar *client_id, GType service_type)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (client_id != NULL && *client_id != '\0', NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_type_is_a (service_type, GDATA_TYPE_SERVICE), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return gdata_client_login_authorizer_new_for_authorization_domains (client_id,
|
|
Packit |
4b6dd7 |
gdata_service_get_authorization_domains (service_type));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_new_for_authorization_domains:
|
|
Packit |
4b6dd7 |
* @client_id: your application's client ID
|
|
Packit |
4b6dd7 |
* @authorization_domains: (element-type GDataAuthorizationDomain) (transfer none): a non-empty list of #GDataAuthorizationDomains to be
|
|
Packit |
4b6dd7 |
* authorized against by the #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Creates a new #GDataClientLoginAuthorizer. The @client_id must be unique for your application, and as registered with Google. This function is
|
|
Packit |
4b6dd7 |
* intended to be used only when the default authorization domain list for a single #GDataService, as used by gdata_client_login_authorizer_new(),
|
|
Packit |
4b6dd7 |
* isn't suitable. For example, this could be because the #GDataClientLoginAuthorizer will be used with multiple #GDataService subclasses, or because
|
|
Packit |
4b6dd7 |
* the client requires a specific set of authorization domains.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The specified #GDataAuthorizationDomains are the ones the user will be logged in to using the provided username and password when
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_authenticate() is called. Note that the same username and password will be used for all domains.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): a new #GDataClientLoginAuthorizer, or %NULL; unref with g_object_unref()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizer *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_new_for_authorization_domains (const gchar *client_id, GList *authorization_domains)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GList *i;
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizer *authorizer;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (client_id != NULL && *client_id != '\0', NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (authorization_domains != NULL, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
authorizer = GDATA_CLIENT_LOGIN_AUTHORIZER (g_object_new (GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER,
|
|
Packit |
4b6dd7 |
"client-id", client_id,
|
|
Packit |
4b6dd7 |
NULL));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Register all the domains with the authorizer */
|
|
Packit |
4b6dd7 |
for (i = authorization_domains; i != NULL; i = i->next) {
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_AUTHORIZATION_DOMAIN (i->data), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* We don't have to lock the authoriser's mutex here as no other code has seen the authoriser yet */
|
|
Packit |
4b6dd7 |
g_hash_table_insert (authorizer->priv->auth_tokens, g_object_ref (GDATA_AUTHORIZATION_DOMAIN (i->data)), NULL);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return authorizer;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Called in the main thread to notify of changes to the username and password properties from the authentication thread. It swallows a reference
|
|
Packit |
4b6dd7 |
* the authoriser. */
|
|
Packit |
4b6dd7 |
static gboolean
|
|
Packit |
4b6dd7 |
notify_authentication_details_cb (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GObject *authorizer = G_OBJECT (self);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_freeze_notify (authorizer);
|
|
Packit |
4b6dd7 |
g_object_notify (authorizer, "username");
|
|
Packit |
4b6dd7 |
g_object_notify (authorizer, "password");
|
|
Packit |
4b6dd7 |
g_object_thaw_notify (authorizer);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_unref (self);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Only execute once */
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
set_authentication_details (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password, GHashTable *new_auth_tokens,
|
|
Packit |
4b6dd7 |
gboolean is_async)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = self->priv;
|
|
Packit |
4b6dd7 |
GHashTableIter iter;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_rec_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Ensure the username is always a full e-mail address */
|
|
Packit |
4b6dd7 |
g_free (priv->username);
|
|
Packit |
4b6dd7 |
if (username != NULL && strchr (username, '@') == NULL) {
|
|
Packit |
4b6dd7 |
priv->username = g_strdup_printf ("%s@" EMAIL_DOMAIN, username);
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
priv->username = g_strdup (username);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (priv->password);
|
|
Packit |
4b6dd7 |
priv->password = _gdata_service_secure_strdup (password);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Transfer all successful auth. tokens to the object-wide auth. token store. */
|
|
Packit |
4b6dd7 |
if (new_auth_tokens == NULL) {
|
|
Packit |
4b6dd7 |
/* Reset ->auth_tokens to contain no auth. tokens, just the domains. */
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->auth_tokens);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, NULL, NULL) == TRUE) {
|
|
Packit |
4b6dd7 |
g_hash_table_iter_replace (&iter, NULL);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
/* Replace the existing ->auth_tokens with the new one, which contains all the shiny new auth. tokens. */
|
|
Packit |
4b6dd7 |
g_hash_table_ref (new_auth_tokens);
|
|
Packit |
4b6dd7 |
g_hash_table_unref (priv->auth_tokens);
|
|
Packit |
4b6dd7 |
priv->auth_tokens = new_auth_tokens;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_rec_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Notify of the property changes in the main thread; i.e. if we're running an async operation, schedule the notification in an idle
|
|
Packit |
4b6dd7 |
* callback; but if we're running a sync operation, emit them immediately.
|
|
Packit |
4b6dd7 |
* This guarantees that:
|
|
Packit |
4b6dd7 |
* • notifications will always be emitted before gdata_client_login_authorizer_authenticate() returns; and
|
|
Packit |
4b6dd7 |
* • notifications will always be emitted in the main thread for calls to gdata_client_login_authorizer_authenticate_async(). */
|
|
Packit |
4b6dd7 |
if (is_async == TRUE) {
|
|
Packit |
4b6dd7 |
g_idle_add ((GSourceFunc) notify_authentication_details_cb, g_object_ref (self));
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
notify_authentication_details_cb (g_object_ref (self));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static GDataSecureString
|
|
Packit |
4b6dd7 |
parse_authentication_response (GDataClientLoginAuthorizer *self, GDataAuthorizationDomain *domain, guint status,
|
|
Packit |
4b6dd7 |
const gchar *response_body, gint length, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
gchar *auth_start, *auth_end;
|
|
Packit |
4b6dd7 |
GDataSecureString auth_token; /* NOTE: auth_token must be allocated using _gdata_service_secure_strdup() and friends */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Parse the response */
|
|
Packit |
4b6dd7 |
auth_start = strstr (response_body, "Auth=");
|
|
Packit |
4b6dd7 |
if (auth_start == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
auth_start += strlen ("Auth=");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
auth_end = strstr (auth_start, "\n");
|
|
Packit |
4b6dd7 |
if (auth_end == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
auth_token = _gdata_service_secure_strndup (auth_start, auth_end - auth_start);
|
|
Packit |
4b6dd7 |
if (auth_token == NULL || strlen (auth_token) == 0) {
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (auth_token);
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return auth_token;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
protocol_error:
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
|
|
Packit |
4b6dd7 |
_("The server returned a malformed response."));
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
parse_error_response (GDataClientLoginAuthorizer *self, guint status, const gchar *reason_phrase, const gchar *response_body, gint length,
|
|
Packit |
4b6dd7 |
GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
/* We prefer to include the @response_body in the error message, but if it's empty, fall back to the @reason_phrase */
|
|
Packit |
4b6dd7 |
if (response_body == NULL || *response_body == '\0') {
|
|
Packit |
4b6dd7 |
response_body = reason_phrase;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* See: http://code.google.com/apis/gdata/docs/2.0/reference.html#HTTPStatusCodes */
|
|
Packit |
4b6dd7 |
switch (status) {
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_CANT_RESOLVE:
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_CANT_CONNECT:
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_SSL_FAILED:
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_IO_ERROR:
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_NETWORK_ERROR,
|
|
Packit |
4b6dd7 |
_("Cannot connect to the service’s server."));
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_CANT_RESOLVE_PROXY:
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_CANT_CONNECT_PROXY:
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROXY_ERROR,
|
|
Packit |
4b6dd7 |
_("Cannot connect to the proxy server."));
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_MALFORMED:
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_BAD_REQUEST: /* 400 */
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is an error message returned by the server. */
|
|
Packit |
4b6dd7 |
_("Invalid request URI or header, or unsupported nonstandard parameter: %s"), response_body);
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_UNAUTHORIZED: /* 401 */
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_FORBIDDEN: /* 403 */
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is an error message returned by the server. */
|
|
Packit |
4b6dd7 |
_("Authentication required: %s"), response_body);
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_NOT_FOUND: /* 404 */
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_NOT_FOUND,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is an error message returned by the server. */
|
|
Packit |
4b6dd7 |
_("The requested resource was not found: %s"), response_body);
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_CONFLICT: /* 409 */
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_PRECONDITION_FAILED: /* 412 */
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_CONFLICT,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is an error message returned by the server. */
|
|
Packit |
4b6dd7 |
_("The entry has been modified since it was downloaded: %s"), response_body);
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
case SOUP_STATUS_INTERNAL_SERVER_ERROR: /* 500 */
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We'll fall back to a generic error, below */
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* If the error hasn't been handled already, throw a generic error */
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
|
|
Packit |
4b6dd7 |
/* Translators: the first parameter is an HTTP status,
|
|
Packit |
4b6dd7 |
* and the second is an error message returned by the server. */
|
|
Packit |
4b6dd7 |
_("Error code %u when authenticating: %s"), status, response_body);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static GDataSecureString
|
|
Packit |
4b6dd7 |
authenticate (GDataClientLoginAuthorizer *self, GDataAuthorizationDomain *domain, const gchar *username, const gchar *password,
|
|
Packit |
4b6dd7 |
gchar *captcha_token, gchar *captcha_answer, GCancellable *cancellable, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = self->priv;
|
|
Packit |
4b6dd7 |
SoupMessage *message;
|
|
Packit |
4b6dd7 |
gchar *request_body;
|
|
Packit |
4b6dd7 |
const gchar *service_name;
|
|
Packit |
4b6dd7 |
guint status;
|
|
Packit |
4b6dd7 |
GDataSecureString auth_token;
|
|
Packit |
4b6dd7 |
SoupURI *_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Prepare the request.
|
|
Packit |
4b6dd7 |
* NOTE: At this point, our non-pageable password is copied into a pageable HTTP request structure. We can't do much about this
|
|
Packit |
4b6dd7 |
* except note that the request is transient and so the chance of it getting paged out is low (but still positive). */
|
|
Packit |
4b6dd7 |
service_name = gdata_authorization_domain_get_service_name (domain);
|
|
Packit |
4b6dd7 |
request_body = soup_form_encode ("accountType", "HOSTED_OR_GOOGLE",
|
|
Packit |
4b6dd7 |
"Email", username,
|
|
Packit |
4b6dd7 |
"Passwd", password,
|
|
Packit |
4b6dd7 |
"service", service_name,
|
|
Packit |
4b6dd7 |
"source", priv->client_id,
|
|
Packit |
4b6dd7 |
(captcha_token == NULL) ? NULL : "logintoken", captcha_token,
|
|
Packit |
4b6dd7 |
"loginanswer", captcha_answer,
|
|
Packit |
4b6dd7 |
NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Free the CAPTCHA token and answer if necessary */
|
|
Packit |
4b6dd7 |
g_free (captcha_token);
|
|
Packit |
4b6dd7 |
g_free (captcha_answer);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the message */
|
|
Packit |
4b6dd7 |
_uri = soup_uri_new ("https://www.google.com/accounts/ClientLogin");
|
|
Packit |
4b6dd7 |
soup_uri_set_port (_uri, _gdata_service_get_https_port ());
|
|
Packit |
4b6dd7 |
message = soup_message_new_from_uri (SOUP_METHOD_POST, _uri);
|
|
Packit |
4b6dd7 |
soup_uri_free (_uri);
|
|
Packit |
4b6dd7 |
soup_message_set_request (message, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, request_body, strlen (request_body));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Send the message */
|
|
Packit |
4b6dd7 |
_gdata_service_actually_send_message (priv->session, message, cancellable, error);
|
|
Packit |
4b6dd7 |
status = message->status_code;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (status == SOUP_STATUS_CANCELLED) {
|
|
Packit |
4b6dd7 |
/* Cancelled (the error has already been set) */
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
} else if (status != SOUP_STATUS_OK) {
|
|
Packit |
4b6dd7 |
const gchar *response_body = message->response_body->data;
|
|
Packit |
4b6dd7 |
gchar *error_start, *error_end, *uri_start, *uri_end, *uri = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Parse the error response; see: http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Errors */
|
|
Packit |
4b6dd7 |
if (response_body == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Error */
|
|
Packit |
4b6dd7 |
error_start = strstr (response_body, "Error=");
|
|
Packit |
4b6dd7 |
if (error_start == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
error_start += strlen ("Error=");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
error_end = strstr (error_start, "\n");
|
|
Packit |
4b6dd7 |
if (error_end == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (strncmp (error_start, "CaptchaRequired", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
const gchar *captcha_base_uri = "http://www.google.com/accounts/";
|
|
Packit |
4b6dd7 |
gchar *captcha_start, *captcha_end, *captcha_uri, *new_captcha_answer;
|
|
Packit |
4b6dd7 |
guint captcha_base_uri_length;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* CAPTCHA required to log in */
|
|
Packit |
4b6dd7 |
captcha_start = strstr (response_body, "CaptchaUrl=");
|
|
Packit |
4b6dd7 |
if (captcha_start == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
captcha_start += strlen ("CaptchaUrl=");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
captcha_end = strstr (captcha_start, "\n");
|
|
Packit |
4b6dd7 |
if (captcha_end == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Do some fancy memory stuff to save ourselves another alloc */
|
|
Packit |
4b6dd7 |
captcha_base_uri_length = strlen (captcha_base_uri);
|
|
Packit |
4b6dd7 |
captcha_uri = g_malloc (captcha_base_uri_length + (captcha_end - captcha_start) + 1);
|
|
Packit |
4b6dd7 |
memcpy (captcha_uri, captcha_base_uri, captcha_base_uri_length);
|
|
Packit |
4b6dd7 |
memcpy (captcha_uri + captcha_base_uri_length, captcha_start, (captcha_end - captcha_start));
|
|
Packit |
4b6dd7 |
captcha_uri[captcha_base_uri_length + (captcha_end - captcha_start)] = '\0';
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Request a CAPTCHA answer from the application */
|
|
Packit |
4b6dd7 |
g_signal_emit (self, authorizer_signals[SIGNAL_CAPTCHA_CHALLENGE], 0, captcha_uri, &new_captcha_answer);
|
|
Packit |
4b6dd7 |
g_free (captcha_uri);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (new_captcha_answer == NULL || *new_captcha_answer == '\0') {
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_CAPTCHA_REQUIRED,
|
|
Packit |
4b6dd7 |
/* Translators: see http://en.wikipedia.org/wiki/CAPTCHA for information about CAPTCHAs */
|
|
Packit |
4b6dd7 |
_("A CAPTCHA must be filled out to log in."));
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Get the CAPTCHA token */
|
|
Packit |
4b6dd7 |
captcha_start = strstr (response_body, "CaptchaToken=");
|
|
Packit |
4b6dd7 |
if (captcha_start == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
captcha_start += strlen ("CaptchaToken=");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
captcha_end = strstr (captcha_start, "\n");
|
|
Packit |
4b6dd7 |
if (captcha_end == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Save the CAPTCHA token and answer, and attempt to log in with them */
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return authenticate (self, domain, username, password,
|
|
Packit |
4b6dd7 |
g_strndup (captcha_start, captcha_end - captcha_start), new_captcha_answer,
|
|
Packit |
4b6dd7 |
cancellable, error);
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "Unknown", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "BadAuthentication", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
/* Looks like Error=BadAuthentication errors don't return a URI */
|
|
Packit |
4b6dd7 |
gchar *info_start, *info_end;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
info_start = strstr (response_body, "Info=");
|
|
Packit |
4b6dd7 |
if (info_start != NULL) {
|
|
Packit |
4b6dd7 |
info_start += strlen ("Info=");
|
|
Packit |
4b6dd7 |
info_end = strstr (info_start, "\n");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* If Info=InvalidSecondFactor, the user needs to generate an application-specific password and use that instead */
|
|
Packit |
4b6dd7 |
if (info_start != NULL && info_end != NULL && strncmp (info_start, "InvalidSecondFactor", info_end - info_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_INVALID_SECOND_FACTOR,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("This account requires an application-specific password. (%s)"),
|
|
Packit |
4b6dd7 |
"http://www.google.com/support/accounts/bin/static.py?page=guide.cs&guide=1056283&topic=1056286");
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Fall back to a generic "bad authentication details" message */
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION,
|
|
Packit |
4b6dd7 |
_("Your username or password were incorrect."));
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Get the information URI */
|
|
Packit |
4b6dd7 |
uri_start = strstr (response_body, "Url=");
|
|
Packit |
4b6dd7 |
if (uri_start == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
uri_start += strlen ("Url=");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
uri_end = strstr (uri_start, "\n");
|
|
Packit |
4b6dd7 |
if (uri_end == NULL) {
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
uri = g_strndup (uri_start, uri_end - uri_start);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (strncmp (error_start, "NotVerified", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_NOT_VERIFIED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("Your account’s e-mail address has not been verified. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "TermsNotAgreed", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_TERMS_NOT_AGREED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("You have not agreed to the service’s terms and conditions. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "AccountMigrated", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
/* This is non-standard, and used by YouTube since it's got messed-up accounts */
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_MIGRATED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("This account has been migrated. Please log in online to receive your new username and password. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "AccountDeleted", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DELETED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("This account has been deleted. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "AccountDisabled", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DISABLED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("This account has been disabled. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "ServiceDisabled", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_SERVICE_DISABLED,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("This account’s access to this service has been disabled. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
} else if (strncmp (error_start, "ServiceUnavailable", error_end - error_start) == 0) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_UNAVAILABLE,
|
|
Packit |
4b6dd7 |
/* Translators: the parameter is a URI for further information. */
|
|
Packit |
4b6dd7 |
_("This service is not available at the moment. (%s)"), uri);
|
|
Packit |
4b6dd7 |
goto login_error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Unknown error type! */
|
|
Packit |
4b6dd7 |
goto protocol_error;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
login_error:
|
|
Packit |
4b6dd7 |
g_free (uri);
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_assert (message->response_body->data != NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
auth_token = parse_authentication_response (self, domain, status, message->response_body->data, message->response_body->length, error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Zero out the response body to lower the chance of it (with all the juicy passwords and auth. tokens it contains) hitting disk or getting
|
|
Packit |
4b6dd7 |
* leaked in free memory. */
|
|
Packit |
4b6dd7 |
memset ((void*) message->response_body->data, 0, message->response_body->length);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return auth_token;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
protocol_error:
|
|
Packit |
4b6dd7 |
parse_error_response (self, status, message->reason_phrase, message->response_body->data, message->response_body->length, error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static gboolean
|
|
Packit |
4b6dd7 |
authenticate_loop (GDataClientLoginAuthorizer *authorizer, gboolean is_async, const gchar *username, const gchar *password, GCancellable *cancellable,
|
|
Packit |
4b6dd7 |
GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizerPrivate *priv = authorizer->priv;
|
|
Packit |
4b6dd7 |
gboolean cumulative_success = TRUE;
|
|
Packit |
4b6dd7 |
GHashTable *new_auth_tokens;
|
|
Packit |
4b6dd7 |
GHashTableIter iter;
|
|
Packit |
4b6dd7 |
GDataAuthorizationDomain *domain;
|
|
Packit |
4b6dd7 |
GDataSecureString auth_token;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_rec_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Authenticate and authorize against each of the services registered with the authorizer */
|
|
Packit |
4b6dd7 |
new_auth_tokens = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) _gdata_service_secure_strfree);
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->auth_tokens);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, (gpointer*) &domain, NULL) == TRUE) {
|
|
Packit |
4b6dd7 |
GError *authenticate_error = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
auth_token = authenticate (authorizer, domain, username, password, NULL, NULL, cancellable, &authenticate_error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (auth_token == NULL && cumulative_success == TRUE) {
|
|
Packit |
4b6dd7 |
/* Only propagate the first error which occurs. */
|
|
Packit |
4b6dd7 |
g_propagate_error (error, authenticate_error);
|
|
Packit |
4b6dd7 |
authenticate_error = NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
cumulative_success = (auth_token != NULL) && cumulative_success;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Store the auth. token (or lack thereof if authentication failed). */
|
|
Packit |
4b6dd7 |
g_hash_table_insert (new_auth_tokens, g_object_ref (domain), auth_token);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_clear_error (&authenticate_error);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_rec_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set or clear the authentication details and return now that we're done */
|
|
Packit |
4b6dd7 |
if (cumulative_success == TRUE) {
|
|
Packit |
4b6dd7 |
set_authentication_details (authorizer, username, password, new_auth_tokens, is_async);
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
set_authentication_details (authorizer, NULL, NULL, NULL, is_async);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_unref (new_auth_tokens);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return cumulative_success;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
typedef struct {
|
|
Packit |
4b6dd7 |
gchar *username;
|
|
Packit |
4b6dd7 |
GDataSecureString password; /* NOTE: This must be allocated in non-pageable memory using _gdata_service_secure_strdup(). */
|
|
Packit |
4b6dd7 |
} AuthenticateAsyncData;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
authenticate_async_data_free (AuthenticateAsyncData *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_free (self->username);
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (self->password);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_slice_free (AuthenticateAsyncData, self);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
authenticate_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataClientLoginAuthorizer *authorizer = GDATA_CLIENT_LOGIN_AUTHORIZER (source_object);
|
|
Packit |
4b6dd7 |
g_autoptr(GError) error = NULL;
|
|
Packit |
4b6dd7 |
AuthenticateAsyncData *data = task_data;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (!authenticate_loop (authorizer, TRUE, data->username, data->password, cancellable, &error))
|
|
Packit |
4b6dd7 |
g_task_return_error (task, g_steal_pointer (&error));
|
|
Packit |
4b6dd7 |
else
|
|
Packit |
4b6dd7 |
g_task_return_boolean (task, TRUE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_authenticate_async:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
* @username: the user's username
|
|
Packit |
4b6dd7 |
* @password: the user's password
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): optional #GCancellable object, or %NULL
|
|
Packit |
4b6dd7 |
* @callback: a #GAsyncReadyCallback to call when authentication is finished
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Authenticates the #GDataClientLoginAuthorizer with the Google accounts service using the given @username and @password. @self, @username and
|
|
Packit |
4b6dd7 |
* @password are all reffed/copied when this function is called, so can safely be freed after this function returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* For more details, see gdata_client_login_authorizer_authenticate(), which is the synchronous version of this function.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* When the operation is finished, @callback will be called. You can then call gdata_client_login_authorizer_authenticate_finish()
|
|
Packit |
4b6dd7 |
* to get the results of the operation.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_authenticate_async (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password,
|
|
Packit |
4b6dd7 |
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_autoptr(GTask) task = NULL;
|
|
Packit |
4b6dd7 |
AuthenticateAsyncData *data;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (username != NULL);
|
|
Packit |
4b6dd7 |
g_return_if_fail (password != NULL);
|
|
Packit |
4b6dd7 |
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
data = g_slice_new (AuthenticateAsyncData);
|
|
Packit |
4b6dd7 |
data->username = g_strdup (username);
|
|
Packit |
4b6dd7 |
data->password = _gdata_service_secure_strdup (password);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
task = g_task_new (self, cancellable, callback, user_data);
|
|
Packit |
4b6dd7 |
g_task_set_source_tag (task, gdata_client_login_authorizer_authenticate_async);
|
|
Packit |
4b6dd7 |
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) authenticate_async_data_free);
|
|
Packit |
4b6dd7 |
g_task_run_in_thread (task, authenticate_thread);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_authenticate_finish:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
* @async_result: a #GAsyncResult
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Finishes an asynchronous authentication operation started with gdata_client_login_authorizer_authenticate_async().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: %TRUE if authentication was successful, %FALSE otherwise
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gboolean
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_authenticate_finish (GDataClientLoginAuthorizer *self, GAsyncResult *async_result, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_task_is_valid (async_result, self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_client_login_authorizer_authenticate_async), FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return g_task_propagate_boolean (G_TASK (async_result), error);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_authenticate:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
* @username: the user's username
|
|
Packit |
4b6dd7 |
* @password: the user's password
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): optional #GCancellable object, or %NULL
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Authenticates the #GDataClientLoginAuthorizer with the Google Accounts service using @username and @password and authorizes it against all the
|
|
Packit |
4b6dd7 |
* service types passed to gdata_client_login_authorizer_new(); i.e. logs into the service with the given user account. @username should be a full
|
|
Packit |
4b6dd7 |
* e-mail address (e.g. <literal>john.smith\@gmail.com</literal>). If a full e-mail address is not given, @username will have
|
|
Packit |
4b6dd7 |
* <literal>\@gmail.com</literal> appended to create an e-mail address
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If @cancellable is not %NULL, then the operation can be cancelled by triggering the @cancellable object from another thread.
|
|
Packit |
4b6dd7 |
* If the operation was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If the operation errors or is cancelled part-way through, gdata_authorizer_is_authorized_for_domain() is guaranteed to return %FALSE
|
|
Packit |
4b6dd7 |
* for all #GDataAuthorizationDomains, even if authentication has succeeded for some of them already.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* A %GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION will be returned if authentication failed due to an incorrect username or password.
|
|
Packit |
4b6dd7 |
* Other #GDataClientLoginAuthorizerError errors can be returned for other conditions.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If the service requires a CAPTCHA to be completed, the #GDataClientLoginAuthorizer::captcha-challenge signal will be emitted.
|
|
Packit |
4b6dd7 |
* The return value from a signal handler for the signal should be a newly allocated string containing the text from the image. If the text is %NULL
|
|
Packit |
4b6dd7 |
* or empty, authentication will fail with a %GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_CAPTCHA_REQUIRED error. Otherwise, authentication will be
|
|
Packit |
4b6dd7 |
* automatically and transparently restarted with the new CAPTCHA details.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* A %GDATA_SERVICE_ERROR_PROTOCOL_ERROR will be returned if the server's responses were invalid.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: %TRUE if authentication and authorization was successful against all the services, %FALSE otherwise
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gboolean
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_authenticate (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password,
|
|
Packit |
4b6dd7 |
GCancellable *cancellable, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (username != NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (password != NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return authenticate_loop (self, FALSE, username, password, cancellable, error);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
notify_proxy_uri_cb (GObject *object, GParamSpec *pspec, GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
/* Flush our cached version */
|
|
Packit |
4b6dd7 |
if (self->priv->proxy_uri != NULL) {
|
|
Packit |
4b6dd7 |
soup_uri_free (self->priv->proxy_uri);
|
|
Packit |
4b6dd7 |
self->priv->proxy_uri = NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_notify (G_OBJECT (self), "proxy-uri");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Static function which isn't deprecated so we can continue using it internally. */
|
|
Packit |
4b6dd7 |
static SoupURI *
|
|
Packit |
4b6dd7 |
_get_proxy_uri (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
SoupURI *proxy_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* If we have a cached version, return that */
|
|
Packit |
4b6dd7 |
if (self->priv->proxy_uri != NULL) {
|
|
Packit |
4b6dd7 |
return self->priv->proxy_uri;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_get (self->priv->session, SOUP_SESSION_PROXY_URI, &proxy_uri, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Update the cache; it takes ownership of the URI */
|
|
Packit |
4b6dd7 |
self->priv->proxy_uri = proxy_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return proxy_uri;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_get_proxy_uri:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the proxy URI on the #GDataClientLoginAuthorizer's #SoupSession.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): the proxy URI, or %NULL; free with soup_uri_free()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
* Deprecated: 0.15.0: Use gdata_client_login_authorizer_get_proxy_resolver() instead, which gives more flexibility over the proxy used.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
SoupURI *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_get_proxy_uri (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
return _get_proxy_uri (self);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Static function which isn't deprecated so we can continue using it internally. */
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
_set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_set (self->priv->session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Notification is handled in notify_proxy_uri_cb() which is called as a result of setting the property on the session */
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_set_proxy_uri:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
* @proxy_uri: (allow-none): the proxy URI, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Sets the proxy URI on the #SoupSession used internally by the #GDataClientLoginAuthorizer. This forces all requests through the given proxy.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If @proxy_uri is %NULL, no proxy will be used.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
* Deprecated: 0.15.0: Use gdata_client_login_authorizer_set_proxy_resolver() instead, which gives more flexibility over the proxy used.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
_set_proxy_uri (self, proxy_uri);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_get_proxy_resolver:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GProxyResolver on the #GDataClientLoginAuthorizer's #SoupSession.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer none) (allow-none): a #GProxyResolver, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.15.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GProxyResolver *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_get_proxy_resolver (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return self->priv->proxy_resolver;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_set_proxy_resolver:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
* @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Sets the #GProxyResolver on the #SoupSession used internally by the given #GDataClientLoginAuthorizer.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Setting this will clear the #GDataClientLoginAuthorizer:proxy-uri property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.15.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_set_proxy_resolver (GDataClientLoginAuthorizer *self, GProxyResolver *proxy_resolver)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (proxy_resolver == NULL || G_IS_PROXY_RESOLVER (proxy_resolver));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (proxy_resolver != NULL) {
|
|
Packit |
4b6dd7 |
g_object_ref (proxy_resolver);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_clear_object (&self->priv->proxy_resolver);
|
|
Packit |
4b6dd7 |
self->priv->proxy_resolver = proxy_resolver;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_notify (G_OBJECT (self), "proxy-resolver");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_object_notify (self, "timeout");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_get_timeout:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GDataClientLoginAuthorizer:timeout property; the network timeout, in seconds.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the timeout, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
guint
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_get_timeout (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
guint timeout;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), 0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_get (self->priv->session, SOUP_SESSION_TIMEOUT, &timeout, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return timeout;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_set_timeout:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
* @timeout: the timeout, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Sets the #GDataClientLoginAuthorizer:timeout property; the network timeout, in seconds.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If @timeout is 0 , network operations will never time out.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_set_timeout (GDataClientLoginAuthorizer *self, guint timeout)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_set (self->priv->session, SOUP_SESSION_TIMEOUT, timeout, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Notification is handled in notify_proxy_uri_cb() which is called as a result of setting the property on the session */
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_get_client_id:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Returns the authorizer's client ID, as specified on constructing the #GDataClientLoginAuthorizer.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the authorizer's client ID
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
const gchar *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_get_client_id (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return self->priv->client_id;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_get_username:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Returns the username of the currently authenticated user, or %NULL if nobody is authenticated.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* It is not safe to call this while an authentication operation is ongoing.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the username of the currently authenticated user, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
const gchar *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_get_username (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* There's little point protecting this with ->mutex, as the data's meaningless if accessed during an authentication operation,
|
|
Packit |
4b6dd7 |
* and not being accessed concurrently otherwise. */
|
|
Packit |
4b6dd7 |
return self->priv->username;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_client_login_authorizer_get_password:
|
|
Packit |
4b6dd7 |
* @self: a #GDataClientLoginAuthorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Returns the password of the currently authenticated user, or %NULL if nobody is authenticated.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* It is not safe to call this while an authentication operation is ongoing.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If libgdata is compiled with libgcr support, the password will be stored in non-pageable memory. Since this function doesn't return
|
|
Packit |
4b6dd7 |
* a copy of the password, the returned value is guaranteed to not hit disk. It's advised that any copies of the password made in client programs
|
|
Packit |
4b6dd7 |
* also use non-pageable memory.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the password of the currently authenticated user, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
const gchar *
|
|
Packit |
4b6dd7 |
gdata_client_login_authorizer_get_password (GDataClientLoginAuthorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* There's little point protecting this with ->mutex, as the data's meaningless if accessed during an authentication operation,
|
|
Packit |
4b6dd7 |
* and not being accessed concurrently otherwise. */
|
|
Packit |
4b6dd7 |
return self->priv->password;
|
|
Packit |
4b6dd7 |
}
|