1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2012 Intel Corporation.
8 * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27 * SECTION:gsignond-oauth-plugin
28 * @short_description: OAuth1/OAuth2 authentication plugin for gSSO single sign-on service
29 * @see_also: #GSignondPlugin
31 * The OAuth plugin provides a client-side implementation of OAuth 1 and OAuth 2
32 * authorization protocols. The overall flow is that the plugin is requested to
33 * perform authorization using supplied authorization parameters, and if it has
34 * succeeded in doing so, it returns a token string to the application that can
35 * be used to access protected resources over https. The plugin is not involved
36 * in accessing protected resources, only in initial authorization.
38 * OAuth1 is specified in <ulink url="http://tools.ietf.org/html/rfc5849">RFC 5849</ulink>,
39 * OAuth2 is specified in <ulink url="http://tools.ietf.org/html/rfc6749">RFC 6749</ulink>
40 * (with additional info regarding the basic bearer token type in <ulink
41 * url="http://tools.ietf.org/html/rfc6750">RFC6750</ulink>). The two versions are
42 * not compatible and specify significantly different authorization sequences, for
43 * that reason they are implemented as separate mechanisms in the plugin.
45 * The plugin implements the standard #GSignondPlugin interface, and after instantiating
46 * a plugin object all interactions happen through that interface.
48 * #GSignondPlugin:type property of the plugin object is set to "oauth".
50 * #GSignondPlugin:mechanisms property of the plugin object is a list of "oauth1" and "oauth2".
52 * <refsect1><title>Authorization sequence</title></refsect1>
54 * The authorization sequence begins with issuing gsignond_plugin_request_initial().
55 * The @mechanism parameter should be set to "oauth1" or "oauth2", and
56 * the contents of @session_data and @identity_method_cache parameters depend
57 * on the mechanism and are described in detail below.
59 * The plugin responds to the request with one of the following signals:
60 * - #GSignondPlugin::response-final This means the authorization sequence ended
61 * successfully, and the authorization token is delivered in @session_data parameter
62 * of the signal. This signal concludes the sequence.
63 * - #GSignondPlugin::user-action-required The plugin is requesting to perform a
64 * user authorization procedure by opening a webpage in a user-agent (browser) where the user is expected
65 * to enter her credentials. Parameters for this step are specified in @ui_data.
66 * After the user interaction has completed, the results are returned to the
67 * plugin with gsignond_plugin_user_action_finished() method, and the authorization
69 * - #GSignondPlugin::store The plugin is requesting to replace the token cache
70 * with the contents of @identity_method_cache parameter. There is no need to respond to this
71 * signal; the authorization process continues immediately.
72 * - #GSignondPlugin::error An error has happened in the authorization sequence
74 * Typical errors are %GSIGNOND_ERROR_MISSING_DATA which means there wasn't enough
75 * data provided in gsignond_plugin_request_initial() to perform the authorization,
76 * %GSIGNOND_ERROR_NOT_AUTHORIZED which means the server rejected the
77 * authorization attempt, %GSIGNOND_ERROR_USER_INTERACTION which means there
78 * was an error during interaction with the user.
80 * At any point the application can request to stop the authorization by calling
81 * gsignond_plugin_cancel(). The plugin responds with an #GSignondPlugin::error signal
82 * containing a %GSIGNOND_ERROR_SESSION_CANCELED error.
84 * <refsect1><title>Code examples</title></refsect1>
87 * <title>Using OAuth1</title>
89 * <xi:include href="../gsignond-oauth1-example.listing" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/>
94 * <title>Using OAuth2</title>
96 * <xi:include href="../gsignond-oauth2-example.listing" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/>
100 * <refsect1><title>HTTP-related parameters in requests</title></refsect1>
102 * Both OAuth1 and OAuth2 are using HTTP requests for authorization. It's possible
103 * to use the following entries in gsignond_plugin_request_initial() @session_data
104 * parameter to influence those requests:
105 * - gsignond_session_data_set_network_proxy() provides a HTTP proxy to use.
106 * If this parameter is not set, the system proxy configuration is used.
107 * - "SslStrict" key whose value is a gboolean. If set to FALSE, then server
108 * certificates which are invalid (for example, expired, or self-signed)
109 * will not be rejected. If set to TRUE or not set, then server certificates
112 * <refsect1><title>OAuth version 1 parameters for authorization</title></refsect1>
114 * Where not specified otherwise, parameters are strings.
116 * <refsect2><title>Parameters in gsignond_plugin_request_initial() @identity_method_cache</title></refsect2>
118 * This parameter contains a cache of previously received tokens in the form of
119 * a #GSignondDictionary. Tokens are indexed by a ConsumerKey in the dictionary,
120 * and each token is itself a #GSignondDictionary, with keys and values described
121 * below in the token format section.
123 * <refsect2><title>Parameters in gsignond_plugin_request_initial() @session_data</title></refsect2>
125 * - "ConsumerKey" (mandatory) - the identifier portion of the client
126 * credentials (equivalent to a username). Refer to <ulink url=
127 * "http://tools.ietf.org/html/rfc5849#section-3.1">RFC5849 section 3.1</ulink>
128 * - gsignond_session_data_set_ui_policy() (mandatory) - if set to %GSIGNOND_UI_POLICY_DEFAULT
129 * a default authorization sequence is used, which may involve re-using a
130 * previously cached token without making any authorization server requests at all.
131 * If set to %GSIGNOND_UI_POLICY_REQUEST_PASSWORD any cached token corresponding
132 * to the ConsumerKey is discarded and the authorization procedure is started
133 * from the beginning.
134 * - gsignond_session_data_set_allowed_realms (mandatory) - a list of domains that
135 * RequestEndpoint, AuthorizationEndpoint and TokenEndpoint hosts must be in. There
136 * authorization sequence will fail if any of the endpoints is not in this list.
137 * - "Realm" (optional) - a requested realm for the token, as specified in
138 * <ulink url="http://tools.ietf.org/html/rfc5849#section-3.5.1">RFC5849 section 3.5.1.</ulink>
139 * - "RequestEndpoint" (mandatory) - a URL that specifies an endpoint used by
140 * the plugin to obtain a set of temporary credentials, as specified in
141 * <ulink url="http://tools.ietf.org/html/rfc5849#section-2">RFC5849 section 2.</ulink>
142 * The endpoint must use HTTPS scheme.
143 * - "Callback" (mandatory) - a callback URI where the user is redirected after
144 * completing the Resource Owner Authorization step, as specified in
145 * <ulink url="http://tools.ietf.org/html/rfc5849#section-2">RFC5849 section 2.</ulink>
146 * - "SignatureMethod" (mandatory) - one of "PLAINTEXT", "HMAC-SHA1", or
147 * "RSA-SHA1" - a method used used by the plugin to sign the requests.
148 * Specified in <ulink url="http://tools.ietf.org/html/rfc5849#section-3.4">RFC5849 section 3.4.</ulink>
149 * - "ConsumerSecret" (optional) - the shared secret portion of the client
150 * credentials, used to sign requests to the server when using PLAINTEXT or
151 * HMAC-SHA1 signature methods. An empty consumer secret is used if it's not supplied.
152 * - "RSAPrivateKey" (mandatory, if RSA-SHA1 signature method is used) - PEM
153 * formatted X.509 private key, used to sign requests to the server when using
154 * RSA-SHA1 signature methods.
155 * - "AuthorizationEndpoint" (mandatory) - Resource Owner Authorization endpoint,
156 * to which the user (resource owner) is redirected to grant authorization, as specified in
157 * <ulink url="http://tools.ietf.org/html/rfc5849#section-2">RFC5849 section 2.</ulink>
158 * - gsignond_session_data_set_username() and gsignond_session_data_set_secret()
159 * (optional) - these two parameters may be used when opening the authorization
160 * endpoint URI to initialize corresponding fields on the webpage.
161 * - "TokenEndpoint" (mandatory) - a URL that specifies an endpoint used by
162 * the plugin to obtain a set of access credentials, as specified in
163 * <ulink url="http://tools.ietf.org/html/rfc5849#section-2">RFC5849 section 2.</ulink>
165 * <refsect2><title>Parameters for #GSignondPlugin::user-action-required signal issued by plugin</title></refsect2>
166 * - gsignond_signonui_data_set_open_url() (mandatory) - a URI that should be opened in a
167 * user-agent (browser) for the user (resource owner) to authenticate herself.
168 * This URI is taken from "AuthorizationEndpoint" parameter of gsignond_plugin_request_initial()
169 * and additional parameters may be appended to the query component.
170 * - gsignond_signonui_data_set_final_url() (mandatory) - a URI where the user-agent should
171 * be redirected after a successfull authentication by the resource owner. This
172 * expected URI is taken from the "Callback" parameter of gsignond_plugin_request_initial() call
173 * to the plugin.The actual (vs. expected) URI may contain additional parameters in the query
174 * component of the URI that are used to continue the authorization process.
175 * - gsignond_signonui_data_set_username() and gsignond_signonui_data_set_password()
176 * (optional) - these two parameters may be used when opening the URI to initialize
177 * corresponding fields on the webpage.
179 * <refsect2><title>Parameters in gsignond_plugin_user_action_finished() @ui_data </title></refsect2>
181 * - gsignond_signonui_data_set_query_error() (mandatory) - indicates if there
182 * was an error in UI interaction and what it was. May be %SIGNONUI_ERROR_NONE
183 * (which means no error), %SIGNONUI_ERROR_CANCELED or any other error.
184 * - gsignond_signonui_data_get_url_response() (mandatory) - the URI that the user-agent
185 * was redirected to. The callback URI supplied in parameters of
186 * gsignond_plugin_request_initial() must be a prefix of this URI. The URI also
187 * has to contain parameters in the query component that are necessary to continue
188 * the authorization sequence.
190 * <refsect2><title>Token and its parameters in #GSignondPlugin::response-final signal</title></refsect2>
191 * gsignond_plugin_response_final() signal concludes the authorization process
192 * and returns a #GSignondDictionary parameter that contains the access token
193 * and some token parameters:
195 * - "AccessToken" (mandatory) - the token itself
196 * - "TokenSecret" (mandatory) - the token shared-secret, used by the application
197 * to sign requests for protected resources
198 * - "Realm" (optional) - the token realm, as specified in
199 * <ulink url="http://tools.ietf.org/html/rfc5849#section-3.5.1">RFC5849 section 3.5.1.</ulink>
200 * - "TokenParameters" (mandatory) - a #GSignondDictionary containing any
201 * additional parameters returned by the server together with the access token.
202 * This dictionary may be empty, or
203 * if it's not, it typically contains service-specific, non-standardized keys and
206 * <refsect1><title>OAuth version 2 parameters for authorization</title></refsect1>
208 * Where not specified otherwise, parameters are strings.
210 * <refsect2><title>Parameters in gsignond_plugin_request_initial() @identity_method_cache</title></refsect2>
212 * This parameter contains a cache of previously received tokens in the form of
213 * a #GSignondDictionary. The keys are tokens' ClientId and values are also
214 * #GSignondDictionary. Those second-level dictionaries contain token scopes as keys
215 * and tokens as values. This two-level approach is done to allow caching several
216 * tokens with unrelated scopes per client.
218 * Finally, each token is itself a #GSignondDictionary, with keys and values described
219 * below in the token format section.
221 * <refsect2><title>Parameters in gsignond_plugin_request_initial() @session_data</title></refsect2>
223 * - "ClientId" (mandatory) - client identifier as described in
224 * <ulink url="http://tools.ietf.org/html/rfc6749#section-2.2">RFC6749 section 2.2.</ulink>
225 * - "ClientSecret" (optional) - client password as described in
226 * <ulink url="http://tools.ietf.org/html/rfc6749#section-2.3">RFC6749 section 2.3.</ulink>
227 * - gsignond_session_data_set_ui_policy() (mandatory) - if set to %GSIGNOND_UI_POLICY_DEFAULT
228 * a default authorization sequence is used, which may involve re-using a
229 * previously cached token without making any authorization server requests at all.
230 * If set to %GSIGNOND_UI_POLICY_REQUEST_PASSWORD any cached token information
231 * (including a refresh token) corresponding to the ClientId is discarded and
232 * the authorization procedure is started from the beginning.
233 * - gsignond_session_data_set_allowed_realms (mandatory) - a list of domains that
234 * AuthHost and TokenHost must be in. The authorization sequence will fail if
235 * either of the hosts is not in this list.
236 * - "Scope" (optional) - a space-separated list of scopes that are requested
237 * for the token, as specified in
238 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.3">RFC6749 section 3.3.</ulink>
239 * - "ForceClientAuthViaRequestBody" (optional) - by default the clients are authenticated via
240 * HTTP Basic authorization mechanism, as described in
241 * <ulink url="http://tools.ietf.org/html/rfc6749#section-2.3.1">RFC6749 section 2.3.1.</ulink>
242 * The RFC stipulates that all OAuth 2 servers must support this, however, it
243 * was discovered that at least Google and Facebook require
244 * client authorization in the request body (which is, according to standard,
245 * optional and not recommended). If set to TRUE, this parameter forces this
246 * non-compliant client authorization to be used.
247 * - "ForceTokenRefresh" (optional) - normally if the token cache contains a
248 * suitable token, it is returned immediately. If this parameter is set to TRUE,
249 * then a refresh token is always used instead to obtain a new token.
251 * <refsect3><title>Parameters used for authorization code grant or implicit grant flows</title></refsect3>
252 * - "ResponseType" (mandatory) - should be set to "code" or "token" as described in
253 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.1.1">RFC6749 section 3.1.1.</ulink>
254 * - "AuthHost" (mandatory) - hostname component of the authorization endpoint URI, as described in
255 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.1">RFC6749 section 3.1.</ulink>
256 * - "AuthPath" (mandatory) - pathname component of the authorization endpoint URI, as described in
257 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.1">RFC6749 section 3.1.</ulink>
258 * - "AuthPort" (optional) - port component of the authorization endpoint URI, as described in
259 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.1">RFC6749 section 3.1.</ulink>
260 * If not specified, standard https port is used.
261 * - "AuthQuery" (optional) - query component of the authorization endpoint URI, as described in
262 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.1">RFC6749 section 3.1.</ulink>
263 * - "RedirectUri" (optional) - redirection endpoint as described in
264 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.1.2">RFC6749 section 3.1.2.</ulink>
265 * - gsignond_session_data_set_username() and gsignond_session_data_set_secret()
266 * (optional) - these two parameters may be used by UI implementation to
267 * initialize corresponding fields on the webpage when opening the authorization
268 * endpoint URI. Also see "UseLoginHint".
269 * - "UseLoginHint" (optional) - if set to TRUE, add the username (see above) to
270 * the authorization URI as a "login_hint" parameter, so that the authorization
271 * endpoint can pre-fill the login box, or selecte the proper multi-login session.
272 * This is a Google extension specified at
273 * <ulink url="https://developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl">
274 * https://developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl</ulink>.
275 * - "UseDisplay" (optional) - if set to a string, the parameter value is added to the authorization
276 * URI as a "display" parameter. This is a Facebook extension specified at
277 * <ulink url="https://developers.facebook.com/docs/reference/dialogs/oauth/">
278 * https://developers.facebook.com/docs/reference/dialogs/oauth/</ulink>
279 * and it affects the way the authorization page looks. Typical values are "page",
280 * "popup" and "touch".
282 * <refsect3><title>Parameters used for resource owner password credentials grant flow</title></refsect3>
283 * Refer to <ulink url="http://tools.ietf.org/html/rfc6749#section-4.3">RFC6749 section 4.3.</ulink>
284 * - "GrantType" (mandatory) - must be set to "password"
285 * - gsignond_session_data_set_username() and gsignond_session_data_set_secret()
286 * (mandatory) - resource owner username and password
288 * <refsect3><title>Parameters used for client credentials grant flow</title></refsect3>
289 * Refer to <ulink url="http://tools.ietf.org/html/rfc6749#section-4.4">RFC6749 section 4.4.</ulink>
290 * - "GrantType" (mandatory) - must be set to "client_credentials"
292 * <refsect3><title>Parameters used for authorization code, resource owner
293 * password or client credentials grant flows (but not implicit grant flow) </title></refsect3>
295 * - "TokenHost" (mandatory) - hostname component of the token endpoint URI, as described in
296 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.2">RFC6749 section 3.2.</ulink>
297 * - "TokenPath" (mandatory) - pathname component of the token endpoint URI, as described in
298 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.2">RFC6749 section 3.2.</ulink>
299 * - "TokenPort" (optional) - port component of the token endpoint URI, as described in
300 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.2">RFC6749 section 3.2.</ulink>
301 * If not specified, standard https port is used.
302 * - "TokenQuery" (optional) - query component of the token endpoint URI, as described in
303 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.2">RFC6749 section 3.2.</ulink>
305 * <refsect2><title>Parameters for #GSignondPlugin::user-action-required signal issued by plugin</title></refsect2>
306 * This signal is issued only when using authorization code grant or implicit code grant flows,
307 * and contains the following parameters:
308 * - gsignond_signonui_data_set_open_url() (mandatory) - an authorization endpoint URI that should be opened in a
309 * user-agent (browser) for the user (resource owner) to authenticate herself.
310 * This URI is constructed using parameters of gsignond_plugin_request_initial()
311 * and additional parameters may be appended to the query component.
312 * - gsignond_signonui_data_set_final_url() (optional) - a redirection endpoint URI where the user-agent should
313 * be redirected after authentication by the resource owner has finished. This
314 * expected URI is taken from the "RedirectUri" parameter of gsignond_plugin_request_initial() call
315 * to the plugin. The actual (vs. expected) URI may contain additional parameters in the query or fragment
316 * components of the URI that are used to determine the outcome of the authorization process.
317 * - gsignond_signonui_data_set_username() and gsignond_signonui_data_set_password()
318 * (optional) - these two parameters may be used when opening the authorization endpoint URI to initialize
319 * corresponding fields on the webpage.
321 * <refsect2><title>Parameters in gsignond_plugin_user_action_finished() @ui_data </title></refsect2>
323 * This function is called when UI interaction has completed and only when using
324 * authorization code grant or implicit code grant flows.
326 * - gsignond_signonui_data_set_query_error() (mandatory) - indicates if there
327 * was an error in UI interaction and what it was. May be %SIGNONUI_ERROR_NONE
328 * (which means no error), %SIGNONUI_ERROR_CANCELED or any other error.
329 * - gsignond_signonui_data_get_url_response() (mandatory) - the URI that the user-agent
330 * was redirected to. The redirection endpoint URI supplied in parameters of
331 * gsignond_plugin_request_initial() must be a prefix of this URI. The URI also
332 * has to contain parameters in the query component (if using authorization code grant)
333 * or in the fragment component (if using implicit code grant) that are necessary to continue
334 * the authorization sequence. Specific information is provided at
335 * <ulink url="http://tools.ietf.org/html/rfc6749#section-4.1.2">RFC6749 section 4.1.2</ulink>
336 * and <ulink url="http://tools.ietf.org/html/rfc6749#section-4.2.2">RFC6749 section 4.2.2</ulink>
339 * <refsect2><title>Token and its parameters in #GSignondPlugin::response-final signal</title></refsect2>
340 * gsignond_plugin_response_final() signal concludes the authorization process
341 * and returns a #GSignondDictionary parameter that contains the access token
342 * and some token parameters:
344 * - "AccessToken" (mandatory) - the token itself
345 * - "TokenType" (mandatory) - the token type, as specified in
346 * <ulink url="http://tools.ietf.org/html/rfc6749#section-7.1">RFC6749 section 7.1</ulink>.
347 * Currently only one token type is supported (the bearer token, standardizied in
348 * <ulink url="http://tools.ietf.org/html/rfc6750">RFC6750</ulink>).
349 * - "TokenParameters" (mandatory) - a #GSignondDictionary containing any
350 * additional parameters returned by the server together with the access token.
351 * The contents of this parameter is specific to the token type, and for bearer
353 * - "Scope" (optional) - the scopes of the issued token, a space separated list
355 * <ulink url="http://tools.ietf.org/html/rfc6749#section-3.3">RFC6749 section 3.3.</ulink>
356 * - "Timestamp" (mandatory) - a gint64 Unix time specifying the time when token was issued.
357 * A Unix time is the number of seconds that have elapsed since 1970-01-01 00:00:00 UTC.
358 * - "Duration" (optional) - the lifetime in seconds of the access token. If specified, the token
359 * will expire at Timestamp+Duration point in time.
360 * - "RefreshToken" (optional) - refresh token as specified in
361 * <ulink url="http://tools.ietf.org/html/rfc6749#section-6">RFC6749 section 6.</ulink>
363 * <refsect1><title>Plugin API common to OAuth1 and Oauth2</title></refsect1>
365 * <refsect2><title>Parameters of #GSignondPlugin::store signal</title></refsect2>
366 * This signal is issued by the plugin when the token cache needs to be updated.
367 * The parameter is a #GSignondDictionary of tokens. The specific cache format
368 * is same as @identity_method_cache parameter of gsignond_plugin_request_initial()
369 * and is desribed in detail in corresponding OAuth1 and OAuth2 sections.
371 * The token cache should be entirely replaced with the parameter of the signal;
372 * the plugin preserves existing tokens that were supplied to
373 * gsignond_plugin_request_initial() in @identity_method_cache parameter.
375 * <refsect2><title>Errors issued via #GSignondPlugin::error signal</title></refsect2>
376 * At any point in the authorization process the plugin may issue this signal
377 * with an @error parameter that is a #GError. The @error has <literal>domain</literal> field set to
378 * %GSIGNOND_ERROR. <literal>code</literal> field can be one of %GSIGNOND_ERROR_MISSING_DATA
379 * (not enough data was supplied in gsignond_plugin_request_initial()),
380 * %GSIGNOND_ERROR_NOT_AUTHORIZED (there was an error in the authorization
381 * process), %GSIGNOND_ERROR_USER_INTERACTION (there was an error in the interaction
382 * with the user), %GSIGNOND_ERROR_SESSION_CANCELED (the authorization process
383 * was canceled). <literal>message</literal> field tells additional details about the exact cause of the
384 * error, and it's intended to help programming and debugging, but not meant
385 * to be understood by end users directly (although it can be shown to them).
390 #include <gsignond/gsignond-plugin-interface.h>
391 #include "gsignond-oauth-plugin.h"
392 #include <gsignond/gsignond-error.h>
393 #include <gsignond/gsignond-log.h>
395 #include "gsignond-oauth-plugin-oauth1.h"
396 #include "gsignond-oauth-plugin-oauth2.h"
399 static void gsignond_plugin_interface_init (GSignondPluginInterface *iface);
401 G_DEFINE_TYPE_WITH_CODE (GSignondOauthPlugin, gsignond_oauth_plugin,
403 G_IMPLEMENT_INTERFACE (GSIGNOND_TYPE_PLUGIN,
404 gsignond_plugin_interface_init));
406 static void _do_reset(GSignondOauthPlugin *self)
408 if (self->soup_session)
409 soup_session_abort(self->soup_session);
410 _do_reset_oauth2(self);
411 _do_reset_oauth1(self);
415 static void gsignond_oauth_plugin_cancel (GSignondPlugin *self)
417 _do_reset(GSIGNOND_OAUTH_PLUGIN(self));
418 GError* error = g_error_new(GSIGNOND_ERROR,
419 GSIGNOND_ERROR_SESSION_CANCELED,
421 gsignond_plugin_error (self, error);
425 static void gsignond_oauth_plugin_request (
426 GSignondPlugin *plugin, GSignondSessionData *session_data)
428 GError* error = g_error_new(GSIGNOND_ERROR,
429 GSIGNOND_ERROR_WRONG_STATE,
430 "Oauth plugin doesn't support request");
431 gsignond_plugin_error (plugin, error);
436 static void gsignond_oauth_plugin_request_initial (
437 GSignondPlugin *plugin, GSignondSessionData *session_data,
438 GSignondDictionary *token_cache,
439 const gchar *mechanism)
441 GSignondOauthPlugin *self = GSIGNOND_OAUTH_PLUGIN (plugin);
445 const gchar* proxy = gsignond_session_data_get_network_proxy(session_data);
448 uri = soup_uri_new(proxy);
449 g_object_set(self->soup_session, "proxy-uri", uri, NULL);
454 gboolean res = gsignond_dictionary_get_boolean(session_data,
459 g_object_set(self->soup_session, "ssl-strict", ssl_strict, NULL);
461 if (g_strcmp0(mechanism, "oauth2") == 0)
462 _process_oauth2_request(self, session_data, token_cache);
463 else if (g_strcmp0(mechanism, "oauth1") == 0)
464 _process_oauth1_request(self, session_data, token_cache);
466 GError* error = g_error_new(GSIGNOND_ERROR,
467 GSIGNOND_ERROR_MECHANISM_NOT_AVAILABLE,
468 "Requested mechanism is not available");
469 gsignond_plugin_error (plugin, error);
474 static void gsignond_oauth_plugin_user_action_finished (
475 GSignondPlugin *plugin,
476 GSignondSignonuiData *session_data)
478 GSignondOauthPlugin *self = GSIGNOND_OAUTH_PLUGIN (plugin);
480 if (_is_active_oauth2_session(self) == TRUE)
481 _process_oauth2_user_action_finished(self, session_data);
482 else if (_is_active_oauth1_session(self) == TRUE)
483 _process_oauth1_user_action_finished(self, session_data);
485 GError* error = g_error_new(GSIGNOND_ERROR,
486 GSIGNOND_ERROR_WRONG_STATE,
487 "Oauth plugin doesn't support user actions");
488 gsignond_plugin_error (plugin, error);
493 static void gsignond_oauth_plugin_refresh (
494 GSignondPlugin *plugin,
495 GSignondSignonuiData *session_data)
497 GError* error = g_error_new(GSIGNOND_ERROR,
498 GSIGNOND_ERROR_WRONG_STATE,
499 "Oauth plugin doesn't support refresh");
500 gsignond_plugin_error (plugin, error);
506 gsignond_plugin_interface_init (GSignondPluginInterface *iface)
508 iface->cancel = gsignond_oauth_plugin_cancel;
509 iface->request_initial = gsignond_oauth_plugin_request_initial;
510 iface->request = gsignond_oauth_plugin_request;
511 iface->user_action_finished = gsignond_oauth_plugin_user_action_finished;
512 iface->refresh = gsignond_oauth_plugin_refresh;
516 _http_authenticate (SoupSession *session, SoupMessage *msg,
517 SoupAuth *auth, gboolean retrying, gpointer data)
519 GSignondOauthPlugin *self = GSIGNOND_OAUTH_PLUGIN (data);
522 if (_is_active_oauth2_session(self) == TRUE)
523 _oauth2_http_authenticate (self, auth);
526 static void _log_http_traffic(SoupLogger *logger,
527 SoupLoggerLogLevel level,
532 g_debug ("%c %s", direction, data);
536 gsignond_oauth_plugin_init (GSignondOauthPlugin *self)
538 self->oauth2_request = NULL;
539 self->oauth1_request = NULL;
540 self->token_cache = NULL;
542 self->soup_session = soup_session_async_new_with_options (
543 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
544 SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
547 SoupLogger *logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
548 soup_logger_set_printer(logger, _log_http_traffic, NULL, NULL);
549 soup_session_add_feature (self->soup_session, SOUP_SESSION_FEATURE (logger));
550 g_object_unref (logger);
552 g_signal_connect (self->soup_session, "authenticate",
553 G_CALLBACK (_http_authenticate), self);
557 gsignond_oauth_plugin_finalize (GObject *gobject)
559 GSignondOauthPlugin *self = GSIGNOND_OAUTH_PLUGIN (gobject);
561 if (self->oauth2_request)
562 gsignond_dictionary_unref(self->oauth2_request);
563 if (self->oauth1_request)
564 gsignond_dictionary_unref(self->oauth1_request);
565 if (self->token_cache)
566 gsignond_dictionary_unref(self->token_cache);
567 if (self->soup_session)
568 g_object_unref(self->soup_session);
570 /* Chain up to the parent class */
571 G_OBJECT_CLASS (gsignond_oauth_plugin_parent_class)->finalize (gobject);
583 gsignond_oauth_plugin_set_property (GObject *object,
591 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
597 gsignond_oauth_plugin_get_property (GObject *object,
603 gchar *mechanisms[] = {"oauth1", "oauth2", NULL };
608 g_value_set_string (value, "oauth");
610 case PROP_MECHANISMS:
611 g_value_set_boxed (value, mechanisms);
615 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
621 gsignond_oauth_plugin_class_init (GSignondOauthPluginClass *klass)
623 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
625 gobject_class->set_property = gsignond_oauth_plugin_set_property;
626 gobject_class->get_property = gsignond_oauth_plugin_get_property;
627 gobject_class->finalize = gsignond_oauth_plugin_finalize;
629 g_object_class_override_property (gobject_class, PROP_TYPE, "type");
630 g_object_class_override_property (gobject_class, PROP_MECHANISMS,