Fix memleak when setting proxy property
[profile/ivi/gsignond-plugin-oauth.git] / test / oauth2tests.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2012 Intel Corporation.
7  *
8  * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
9  *
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.
14  *
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.
19  *
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
23  * 02110-1301 USA
24  */
25
26 #include <check.h>
27 #include <stdlib.h>
28 #include "gsignond-oauth-plugin.h"
29 #include <gsignond/gsignond-session-data.h>
30 #include <gsignond/gsignond-plugin-interface.h>
31 #include <gsignond/gsignond-error.h>
32 #include <gsignond/gsignond-config.h>
33 #include <gsignond/gsignond-utils.h>
34 #include <libsoup/soup.h>
35
36 static void response_callback(GSignondPlugin* plugin, GSignondSessionData* result,
37                      gpointer user_data)
38 {
39     GSignondSessionData** user_data_p = user_data;
40     *user_data_p = result;
41     gsignond_dictionary_ref(result);
42 }
43
44 static void store_callback(GSignondPlugin* plugin, GSignondSessionData* result,
45                      gpointer user_data)
46 {
47     response_callback(plugin, result, user_data);
48 }
49
50 static void user_action_required_callback(GSignondPlugin* plugin, 
51                                           GSignondSignonuiData* ui_request, 
52                                           gpointer user_data)
53 {
54     GSignondSignonuiData** user_data_p = user_data;
55     *user_data_p = ui_request;
56     gsignond_dictionary_ref(ui_request);
57 }
58
59 static void error_callback(GSignondPlugin* plugin, GError* error,
60                      gpointer user_data)
61 {
62     GError** user_data_p = user_data;
63     *user_data_p = g_error_copy(error);
64 }
65
66 static GVariant* make_normal_token()
67 {
68     GSignondDictionary* token = gsignond_dictionary_new();
69     gsignond_dictionary_set_string(token, "AccessToken", "megaaccesstoken");
70     GDateTime* now = g_date_time_new_now_utc();
71     gsignond_dictionary_set_int64(token, "Timestamp", 
72         g_date_time_to_unix(now));
73     g_date_time_unref(now);
74     gsignond_dictionary_set_int64(token, "Duration", 3600);
75     gsignond_dictionary_set_string(token, "RefreshToken", "megarefreshtoken");
76     gsignond_dictionary_set_string(token, "Scope", "scope1 scope2 scope3");
77     GVariant* token_var = gsignond_dictionary_to_variant(token);
78     gsignond_dictionary_unref(token);
79     return token_var;
80 }
81
82 static GVariant* make_expired_token()
83 {
84     GSignondDictionary* token = gsignond_dictionary_new();
85     gsignond_dictionary_set_string(token, "AccessToken", "megaaccesstoken");
86     GDateTime* now = g_date_time_new_now_utc();
87     gsignond_dictionary_set_int64(token, "Timestamp", 
88         g_date_time_to_unix(now) - 7200);
89     g_date_time_unref(now);
90     gsignond_dictionary_set_int64(token, "Duration", 3600);
91     gsignond_dictionary_set_string(token, "RefreshToken", "megarefreshtoken");
92     gsignond_dictionary_set_string(token, "Scope", "scope1 scope2 scope3");
93     GVariant* token_var = gsignond_dictionary_to_variant(token);
94     gsignond_dictionary_unref(token);
95     return token_var;
96 }
97
98 static GSignondDictionary* make_tokens(const gchar* client_id, GVariant* token)
99 {
100     GSignondDictionary* tokens = gsignond_dictionary_new();
101     GSignondDictionary* client_tokens = gsignond_dictionary_new();
102     gsignond_dictionary_set(client_tokens, "scope1 scope2 scope3", token);
103     gsignond_dictionary_set(tokens, client_id, gsignond_dictionary_to_variant(client_tokens));
104     gsignond_dictionary_unref(client_tokens);
105     return tokens;
106 }
107
108 static GVariant* make_no_refresh_token()
109 {
110     GSignondDictionary* token = gsignond_dictionary_new();
111     gsignond_dictionary_set_string(token, "AccessToken", "megaaccesstoken");
112     GDateTime* now = g_date_time_new_now_utc();
113     gsignond_dictionary_set_int64(token, "Timestamp", 
114         g_date_time_to_unix(now));
115     g_date_time_unref(now);
116     gsignond_dictionary_set_int64(token, "Duration", 3600);
117     gsignond_dictionary_set_string(token, "Scope", "scope1 scope2 scope3");
118     GVariant* token_var = gsignond_dictionary_to_variant(token);
119     gsignond_dictionary_unref(token);
120     return token_var;
121 }
122
123 static GVariant* make_no_refresh_expired_token()
124 {
125     GSignondDictionary* token = gsignond_dictionary_new();
126     gsignond_dictionary_set_string(token, "AccessToken", "megaaccesstoken");
127     GDateTime* now = g_date_time_new_now_utc();
128     gsignond_dictionary_set_int64(token, "Timestamp", 
129         g_date_time_to_unix(now) - 7200);
130     g_date_time_unref(now);
131     gsignond_dictionary_set_int64(token, "Duration", 3600);
132     gsignond_dictionary_set_string(token, "Scope", "scope1 scope2 scope3");
133     GVariant* token_var = gsignond_dictionary_to_variant(token);
134     gsignond_dictionary_unref(token);
135     return token_var;
136 }
137
138 START_TEST (test_oauth2_request)
139 {
140     gpointer plugin;
141     
142     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
143     fail_if(plugin == NULL);
144
145     GSignondSessionData* result = NULL;
146     GSignondSessionData* store = NULL;
147     GSignondSignonuiData* ui_action = NULL;
148     GError* error = NULL;
149
150     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
151     g_signal_connect(plugin, "user-action-required", 
152                      G_CALLBACK(user_action_required_callback), &ui_action);
153     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
154     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
155
156     GSignondSessionData* data = gsignond_dictionary_new();
157
158     // unknown mechanism
159     gsignond_plugin_request_initial(plugin, data, NULL, "unknown-mech");
160
161     fail_if(result != NULL);    
162     fail_if(ui_action != NULL);
163     fail_if(store != NULL);
164     fail_if(error == NULL);
165     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
166                                 GSIGNOND_ERROR_MECHANISM_NOT_AVAILABLE));
167     g_error_free(error);
168     error = NULL;
169     
170     // empty data
171     gsignond_plugin_request_initial(plugin, data, NULL, "oauth2");
172
173     fail_if(result != NULL);    
174     fail_if(ui_action != NULL);
175     fail_if(store != NULL);
176     fail_if(error == NULL);
177     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
178                                 GSIGNOND_ERROR_MISSING_DATA));
179     g_error_free(error);
180     error = NULL;
181     
182     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
183     GSignondDictionary* tokens =  make_tokens("megaclient", make_normal_token());
184     
185     // try using expired token
186     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
187     gsignond_dictionary_unref(tokens);
188     tokens = make_tokens("megaclient", make_no_refresh_expired_token());
189     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
190     fail_if(result != NULL);    
191     fail_if(ui_action != NULL);
192     fail_if(store != NULL);
193     fail_if(error == NULL);
194     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
195                                 GSIGNOND_ERROR_MISSING_DATA));
196     g_error_free(error);
197     error = NULL;
198
199     // try token with incorrect (too narrow) scopes
200     gsignond_dictionary_unref(tokens);
201     tokens = make_tokens("megaclient", make_no_refresh_token());
202     gsignond_dictionary_set_string(data, "Scope", "scope2 scope3 scope4");
203     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
204     fail_if(result != NULL);    
205     fail_if(ui_action != NULL);
206     fail_if(store != NULL);
207     fail_if(error == NULL);
208     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
209                                 GSIGNOND_ERROR_MISSING_DATA));
210     g_error_free(error);
211     error = NULL;
212
213     // try correct token without requesting scopes
214     gsignond_dictionary_remove(data, "Scope");
215     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
216     fail_if(result == NULL);
217     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
218                       "megaaccesstoken") != 0);
219     fail_if(gsignond_dictionary_get(result, "RefreshToken") != NULL);
220     gint64 expires_in;
221     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
222     fail_if(expires_in != 3600);
223     gsignond_dictionary_unref(result);
224     result = NULL;
225     fail_if(ui_action != NULL);
226     fail_if(store != NULL);
227     fail_if(error != NULL);
228     
229     // try correct token with requesting a subset of scopes
230     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
231     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
232     fail_if(result == NULL);
233     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
234                       "megaaccesstoken") != 0);
235     fail_if(gsignond_dictionary_get(result, "RefreshToken") != NULL);
236     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
237     fail_if(expires_in != 3600);
238     gsignond_dictionary_unref(result);
239     result = NULL;
240     fail_if(ui_action != NULL);
241     fail_if(store != NULL);
242     fail_if(error != NULL);
243     
244     //don't reuse token
245     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_REQUEST_PASSWORD);
246     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
247     fail_if(result != NULL);    
248     fail_if(ui_action != NULL);
249     fail_if(store != NULL);
250     fail_if(error == NULL);
251     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
252                                 GSIGNOND_ERROR_MISSING_DATA));
253     fail_if(g_strcmp0(error->message, "Unknown ResponseType or GrantType") != 0);
254     g_error_free(error);
255     error = NULL;
256
257     gsignond_dictionary_unref(data);
258     gsignond_dictionary_unref(tokens);
259     g_object_unref(plugin);
260 }
261 END_TEST
262
263 START_TEST (test_oauth2_allowed_realms)
264 {
265     gpointer plugin;
266     
267     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
268     fail_if(plugin == NULL);
269
270     GSignondSessionData* result = NULL;
271     GSignondSessionData* store = NULL;
272     GSignondSignonuiData* ui_action = NULL;
273     GError* error = NULL;
274
275     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
276     g_signal_connect(plugin, "user-action-required", 
277                      G_CALLBACK(user_action_required_callback), &ui_action);
278     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
279     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
280
281     GSignondSessionData* data = gsignond_dictionary_new();
282     GSignondDictionary* tokens = make_tokens("someclient", make_normal_token());
283     
284     // allowed realms is absent
285     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
286     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
287     gsignond_dictionary_set_string(data, "ResponseType", "code");
288     gsignond_dictionary_set_string(data, "AuthHost", "somehost.somedomain.com");
289     gsignond_dictionary_set_string(data, "AuthPath", "/somepath");
290     
291     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
292     fail_if(result != NULL);
293     fail_if(ui_action != NULL);
294     fail_if(store != NULL);
295     fail_if(error == NULL);
296     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
297                                 GSIGNOND_ERROR_MISSING_DATA));
298     fail_if(g_strcmp0(error->message, "Missing realm list") != 0);
299     g_error_free(error);
300     error = NULL;
301     
302     //allowed realms is empty
303     const gchar *empty_realm_list[] = { NULL };
304     GSequence *allowed_realms = gsignond_copy_array_to_sequence(empty_realm_list);
305     gsignond_session_data_set_allowed_realms(data, allowed_realms);
306     g_sequence_free(allowed_realms);
307
308     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
309     fail_if(result != NULL);
310     fail_if(ui_action != NULL);
311     fail_if(store != NULL);
312     fail_if(error == NULL);
313     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
314                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
315     fail_if(g_strcmp0(error->message, "Unauthorized host") != 0);
316     g_error_free(error);
317     error = NULL;
318
319     //allowed realms does not contain same domain
320     const gchar *non_realm_list[] = { "somedomain1.com", "somedomain2.com", "somedomain3.com", NULL };
321     allowed_realms = gsignond_copy_array_to_sequence(non_realm_list);
322     gsignond_session_data_set_allowed_realms(data, allowed_realms);
323     g_sequence_free(allowed_realms);
324
325     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
326     fail_if(result != NULL);
327     fail_if(ui_action != NULL);
328     fail_if(store != NULL);
329     fail_if(error == NULL);
330     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
331                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
332     fail_if(g_strcmp0(error->message, "Unauthorized host") != 0);
333     g_error_free(error);
334     error = NULL;
335     
336     //allowed realms contains same domain
337     const gchar *realm_list[] = { "otherhost.somedomain.com", "somehost.somedomain.com", "thehost.somedomain.com", NULL };
338     allowed_realms = gsignond_copy_array_to_sequence(realm_list);
339     gsignond_session_data_set_allowed_realms(data, allowed_realms);
340     g_sequence_free(allowed_realms);
341
342     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
343     fail_if(result != NULL);
344     fail_if(ui_action == NULL);
345     gsignond_dictionary_unref(ui_action);
346     ui_action = NULL;
347     fail_if(store != NULL);
348     fail_if(error != NULL);
349
350     gsignond_dictionary_unref(data);
351     gsignond_dictionary_unref(tokens);
352     g_object_unref(plugin);
353 }
354 END_TEST
355
356 START_TEST (test_oauth2_ui_request)
357 {
358     gpointer plugin;
359     
360     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
361     fail_if(plugin == NULL);
362
363     GSignondSessionData* result = NULL;
364     GSignondSessionData* store = NULL;
365     GSignondSignonuiData* ui_action = NULL;
366     GError* error = NULL;
367
368     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
369     g_signal_connect(plugin, "user-action-required", 
370                      G_CALLBACK(user_action_required_callback), &ui_action);
371     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
372     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
373
374     GSignondSessionData* data = gsignond_dictionary_new();
375     GSignondDictionary* tokens = make_tokens("someclient", make_normal_token());
376     
377     // minimum set of input data that's sufficient
378     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
379     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
380     gsignond_dictionary_set_string(data, "ResponseType", "code");
381     gsignond_dictionary_set_string(data, "AuthHost", "somehost");
382     gsignond_dictionary_set_string(data, "AuthPath", "/somepath");
383     const gchar *realm_list[] = { "somehost", NULL };
384     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
385     gsignond_session_data_set_allowed_realms(data, allowed_realms);
386     g_sequence_free(allowed_realms);
387     
388     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
389     fail_if(result != NULL);
390     fail_if(ui_action == NULL);
391     // https://somehost/somepath?response%5Ftype=code&
392     // state=lf7B9OsYHdmzWDEkQjYR0oae6HU%3D&client%5Fid=megaclient
393     SoupURI* uri = soup_uri_new(gsignond_signonui_data_get_open_url(ui_action));
394     fail_if(g_strcmp0(soup_uri_get_scheme(uri), "https") != 0);
395     fail_if(g_strcmp0(soup_uri_get_host(uri), "somehost") != 0);
396     fail_if(g_strcmp0(soup_uri_get_path(uri), "/somepath") != 0);
397     fail_if(soup_uri_get_port(uri) != 443);
398     GHashTable* query = soup_form_decode(soup_uri_get_query(uri));
399     fail_if (query == NULL);
400     fail_if(g_strcmp0(g_hash_table_lookup(query, "response_type"), "code") != 0);
401     fail_if(g_strcmp0(g_hash_table_lookup(query, "client_id"), "megaclient") != 0);
402     const gchar* state = g_hash_table_lookup(query, "state");
403     fail_if(strlen(state) < 28);
404     fail_if(state[strlen(state)-1] != '=');
405     fail_if(g_strcmp0(state, gsignond_dictionary_get_string(data, "_Oauth2State")) != 0);
406     g_hash_table_unref(query);
407     soup_uri_free(uri);
408     gsignond_dictionary_unref(ui_action);
409     ui_action = NULL;
410     fail_if(store != NULL);
411     fail_if(error != NULL);
412
413     //maximum possible set of input data
414     gsignond_dictionary_remove(data, "_Oauth2State");
415     gsignond_dictionary_set_string(data, "ResponseType", "token");
416     gsignond_dictionary_set_uint32(data, "AuthPort", 1234);
417     gsignond_dictionary_set_string(data, "AuthQuery", "queryparam1=value1&queryparam2=value2");
418     gsignond_dictionary_set_string(data, "RedirectUri", "http://somehost/login.html");
419     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
420     gsignond_dictionary_set_boolean(data, "UseLoginHint", TRUE);
421     gsignond_dictionary_set_string(data, "UseDisplay", "popup");
422     gsignond_session_data_set_username(data, "megauser");
423     gsignond_session_data_set_secret(data, "megapassword");    
424
425     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
426     fail_if(result != NULL);
427     fail_if(ui_action == NULL);
428     fail_if(g_strcmp0(gsignond_signonui_data_get_username(ui_action), "megauser") != 0);
429     fail_if(g_strcmp0(gsignond_signonui_data_get_password(ui_action), "megapassword") != 0);
430     fail_if(g_strcmp0(gsignond_signonui_data_get_final_url(ui_action), 
431                       "http://somehost/login.html") != 0);
432
433     //https://somehost:1234/somepath?scope=scope1+scope3&response%5Ftype=token&
434     //state=YSecnz09LD3%2FEGaLfZhRsKeIGtk%3D&queryparam1=value1&queryparam2=value2&
435     //redirect%5Furi=http%3A%2F%2Fsomehost%2Flogin%2Ehtml&client%5Fid=megaclient
436     uri = soup_uri_new(gsignond_signonui_data_get_open_url(ui_action));
437     fail_if(g_strcmp0(soup_uri_get_scheme(uri), "https") != 0);
438     fail_if(g_strcmp0(soup_uri_get_host(uri), "somehost") != 0);
439     fail_if(g_strcmp0(soup_uri_get_path(uri), "/somepath") != 0);
440     fail_if(soup_uri_get_port(uri) != 1234);
441     query = soup_form_decode(soup_uri_get_query(uri));
442     fail_if (query == NULL);
443     fail_if(g_strcmp0(g_hash_table_lookup(query, "scope"), "scope1 scope3") != 0);
444     fail_if(g_strcmp0(g_hash_table_lookup(query, "queryparam1"), "value1") != 0);
445     fail_if(g_strcmp0(g_hash_table_lookup(query, "queryparam2"), "value2") != 0);
446     fail_if(g_strcmp0(g_hash_table_lookup(query, "redirect_uri"), "http://somehost/login.html") != 0);
447     fail_if(g_strcmp0(g_hash_table_lookup(query, "response_type"), "token") != 0);
448     fail_if(g_strcmp0(g_hash_table_lookup(query, "client_id"), "megaclient") != 0);
449     fail_if(g_strcmp0(g_hash_table_lookup(query, "login_hint"), "megauser") != 0);
450     fail_if(g_strcmp0(g_hash_table_lookup(query, "display"), "popup") != 0);
451     state = g_hash_table_lookup(query, "state");
452     fail_if(strlen(state) < 28);
453     fail_if(state[strlen(state)-1] != '=');
454     fail_if(g_strcmp0(state, gsignond_dictionary_get_string(data, "_Oauth2State")) != 0);
455     g_hash_table_unref(query);
456     soup_uri_free(uri);    
457     
458     gsignond_dictionary_unref(ui_action);
459     ui_action = NULL;
460     fail_if(store != NULL);
461     fail_if(error != NULL);
462     
463     gsignond_dictionary_unref(data);
464     gsignond_dictionary_unref(tokens);
465     g_object_unref(plugin);
466 }
467 END_TEST
468
469 START_TEST (test_oauth2_implicit)
470 {
471     gpointer plugin;
472     
473     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
474     fail_if(plugin == NULL);
475
476     GSignondSessionData* result = NULL;
477     GSignondSessionData* store = NULL;
478     GSignondSignonuiData* ui_action = NULL;
479     GError* error = NULL;
480     
481     gchar* url;
482     gchar* params;
483     //gsize len;
484     
485     //GSignondDictionary* store_tokens;
486     GSignondDictionary* token;
487     GSignondDictionary* client_tokens;
488
489     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
490     g_signal_connect(plugin, "user-action-required", 
491                      G_CALLBACK(user_action_required_callback), &ui_action);
492     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
493     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
494
495     GSignondSessionData* data = gsignond_dictionary_new();
496     GSignondDictionary* tokens = make_tokens("someotherclient", 
497                                                         make_no_refresh_expired_token());
498
499     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
500     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
501     gsignond_dictionary_set_string(data, "AuthHost", "somehost");
502     gsignond_dictionary_set_string(data, "AuthPath", "/somepath");
503     gsignond_dictionary_set_string(data, "ResponseType", "token");
504     gsignond_dictionary_set_string(data, "RedirectUri", "http://somehost/login.html");
505     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
506     const gchar *realm_list[] = { "somehost", NULL };
507     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
508     gsignond_session_data_set_allowed_realms(data, allowed_realms);
509     g_sequence_free(allowed_realms);
510
511     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
512     fail_if(result != NULL);
513     fail_if(ui_action == NULL);
514     gsignond_dictionary_unref(ui_action);
515     ui_action = NULL;
516     fail_if(store != NULL);
517     fail_if(error != NULL);
518
519     GSignondSignonuiData* ui_data = gsignond_dictionary_new();
520     //empty ui response
521     gsignond_plugin_user_action_finished(plugin, ui_data);
522     fail_if(result != NULL);
523     fail_if(ui_action != NULL);
524     fail_if(store != NULL);
525     fail_if(error == NULL);
526     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
527                                 GSIGNOND_ERROR_USER_INTERACTION));
528     g_error_free(error);
529     error = NULL;
530     
531     // ui interaction error
532     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
533     fail_if(result != NULL);
534     fail_if(ui_action == NULL);
535     gsignond_dictionary_unref(ui_action);
536     ui_action = NULL;
537     fail_if(store != NULL);
538     fail_if(error != NULL);
539     gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_CANCELED);
540     gsignond_plugin_user_action_finished(plugin, ui_data);
541     fail_if(result != NULL);
542     fail_if(ui_action != NULL);
543     fail_if(store != NULL);
544     fail_if(error == NULL);
545     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
546                                 GSIGNOND_ERROR_SESSION_CANCELED));
547     g_error_free(error);
548     error = NULL;
549     
550     // no error, but missing response URL
551     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
552     fail_if(result != NULL);
553     fail_if(ui_action == NULL);
554     gsignond_dictionary_unref(ui_action);
555     ui_action = NULL;
556     fail_if(store != NULL);
557     fail_if(error != NULL);
558     gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_NONE);
559     gsignond_plugin_user_action_finished(plugin, ui_data);
560     fail_if(result != NULL);
561     fail_if(ui_action != NULL);
562     fail_if(store != NULL);
563     fail_if(error == NULL);
564     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
565                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
566     g_error_free(error);
567     error = NULL;
568     
569     //response URL doesn't match redirect url
570     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
571     fail_if(result != NULL);
572     fail_if(ui_action == NULL);
573     gsignond_dictionary_unref(ui_action);
574     ui_action = NULL;
575     fail_if(store != NULL);
576     fail_if(error != NULL);
577     gsignond_signonui_data_set_url_response(ui_data, "http://wronghost/login.html");
578     gsignond_plugin_user_action_finished(plugin, ui_data);
579     fail_if(result != NULL);
580     fail_if(ui_action != NULL);
581     fail_if(store != NULL);
582     fail_if(error == NULL);
583     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
584                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
585     g_error_free(error);
586     error = NULL;
587
588     //returned state doesn't match generated state
589     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
590     fail_if(result != NULL);
591     fail_if(ui_action == NULL);
592     gsignond_dictionary_unref(ui_action);
593     ui_action = NULL;
594     fail_if(store != NULL);
595     fail_if(error != NULL);
596     gsignond_signonui_data_set_url_response(ui_data, 
597                                             "http://somehost/login.html#state=reallywrongstate");
598     gsignond_plugin_user_action_finished(plugin, ui_data);
599     fail_if(result != NULL);
600     fail_if(ui_action != NULL);
601     fail_if(store != NULL);
602     fail_if(error == NULL);
603     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
604                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
605     g_error_free(error);
606     error = NULL;
607
608     //return an error 
609     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
610     fail_if(result != NULL);
611     fail_if(ui_action == NULL);
612     gsignond_dictionary_unref(ui_action);
613     ui_action = NULL;
614     fail_if(store != NULL);
615     fail_if(error != NULL);
616     params = soup_form_encode("state", 
617                               gsignond_dictionary_get_string(data, "_Oauth2State"),
618                               "error", "someerror",
619                               "error_description", "somedesc",
620                               "error_uri", "someuri",
621                               NULL);
622     url = g_strdup_printf("http://somehost/login.html#%s", params);
623     gsignond_signonui_data_set_url_response(ui_data, url);
624     g_free(url);
625     g_free(params);
626     gsignond_plugin_user_action_finished(plugin, ui_data);
627     fail_if(result != NULL);
628     fail_if(ui_action != NULL);
629     fail_if(store != NULL);
630     fail_if(error == NULL);
631     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
632                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
633     g_error_free(error);
634     error = NULL;
635
636     //no access token
637     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
638     fail_if(result != NULL);
639     fail_if(ui_action == NULL);
640     gsignond_dictionary_unref(ui_action);
641     ui_action = NULL;
642     fail_if(store != NULL);
643     fail_if(error != NULL);
644     params = soup_form_encode("state", 
645                               gsignond_dictionary_get_string(data, "_Oauth2State"),
646                               NULL);
647     url = g_strdup_printf("http://somehost/login.html#%s", params);
648     gsignond_signonui_data_set_url_response(ui_data, url);
649     g_free(url);
650     g_free(params);
651     gsignond_plugin_user_action_finished(plugin, ui_data);
652     fail_if(result != NULL);
653     fail_if(ui_action != NULL);
654     fail_if(store != NULL);
655     fail_if(error == NULL);
656     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
657                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
658     g_error_free(error);
659     error = NULL;
660
661     //access token exists, but no token type
662     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
663     fail_if(result != NULL);
664     fail_if(ui_action == NULL);
665     gsignond_dictionary_unref(ui_action);
666     ui_action = NULL;
667     fail_if(store != NULL);
668     fail_if(error != NULL);
669     params = soup_form_encode("state", 
670                               gsignond_dictionary_get_string(data, "_Oauth2State"),
671                               "access_token", "megatoken",
672                               NULL);
673     url = g_strdup_printf("http://somehost/login.html#%s", params);
674     gsignond_signonui_data_set_url_response(ui_data, url);
675     g_free(url);
676     g_free(params);
677     gsignond_plugin_user_action_finished(plugin, ui_data);
678     fail_if(result != NULL);
679     fail_if(ui_action != NULL);
680     fail_if(store != NULL);
681     fail_if(error == NULL);
682     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
683                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
684     g_error_free(error);
685     error = NULL;
686
687     // unknown token type
688     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
689     fail_if(result != NULL);
690     fail_if(ui_action == NULL);
691     gsignond_dictionary_unref(ui_action);
692     ui_action = NULL;
693     fail_if(store != NULL);
694     fail_if(error != NULL);
695     params = soup_form_encode("state", 
696                               gsignond_dictionary_get_string(data, "_Oauth2State"),
697                               "access_token", "meganewtoken",
698                               "token_type", "strangetokentype",
699                               NULL);
700     url = g_strdup_printf("http://somehost/login.html#%s", params);
701     gsignond_signonui_data_set_url_response(ui_data, url);
702     g_free(url);
703     g_free(params);
704     gsignond_plugin_user_action_finished(plugin, ui_data);
705     fail_if(result != NULL);
706     fail_if(ui_action != NULL);
707     fail_if(store != NULL);
708     fail_if(error == NULL);
709     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
710                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
711     g_error_free(error);
712     error = NULL;
713
714     //return token and token type but no other parameters, with requested scope
715     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
716     fail_if(result != NULL);
717     fail_if(ui_action == NULL);
718     gsignond_dictionary_unref(ui_action);
719     ui_action = NULL;
720     fail_if(store != NULL);
721     fail_if(error != NULL);
722     params = soup_form_encode("state", 
723                               gsignond_dictionary_get_string(data, "_Oauth2State"),
724                               "access_token", "meganewtoken",
725                               "token_type", "Bearer",
726                               NULL);
727     url = g_strdup_printf("http://somehost/login.html#%s", params);
728     gsignond_signonui_data_set_url_response(ui_data, url);
729     g_free(url);
730     g_free(params);
731     gsignond_plugin_user_action_finished(plugin, ui_data);
732     fail_if(result == NULL);
733     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
734                       "meganewtoken") != 0);
735     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
736                       "Bearer") != 0);
737     fail_if(gsignond_dictionary_get(result, "TokenParameters") == NULL);
738     fail_if(gsignond_dictionary_get(result, "Timestamp") == NULL);
739     fail_if(gsignond_dictionary_get(result, "Duration") != NULL);
740     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope3") != 0);
741     fail_if(gsignond_dictionary_get(result, "RefreshToken") != NULL);
742     gsignond_dictionary_unref(result);
743     result = NULL;
744     fail_if(ui_action != NULL);
745     fail_if(store == NULL);
746     fail_if(g_hash_table_size(store) != 2);
747     client_tokens = gsignond_dictionary_new_from_variant(
748         gsignond_dictionary_get(store, "megaclient"));
749     token = gsignond_dictionary_new_from_variant(
750         gsignond_dictionary_get(client_tokens, "scope1 scope3"));
751     fail_if(token == NULL);
752     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
753                       "meganewtoken") != 0);
754     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
755                       "Bearer") != 0);
756     fail_if(gsignond_dictionary_get(token, "TokenParameters") == NULL);
757     fail_if(gsignond_dictionary_get(token, "Timestamp") == NULL);
758     fail_if(gsignond_dictionary_get(token, "Duration") != NULL);
759     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope3") != 0);
760     fail_if(gsignond_dictionary_get(token, "RefreshToken") != NULL);
761     
762     gsignond_dictionary_unref(token);
763     gsignond_dictionary_unref(client_tokens);
764
765     gsignond_dictionary_unref(store);
766     store = NULL;
767     fail_if(error != NULL);
768     
769     //return token and token type but no other parameters, with
770     //no requested scope
771     gsignond_dictionary_remove(tokens, "megaclient");
772     gsignond_dictionary_remove(data, "Scope");
773     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
774     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
775     fail_if(result != NULL);
776     fail_if(ui_action == NULL);
777     gsignond_dictionary_unref(ui_action);
778     ui_action = NULL;
779     fail_if(store != NULL);
780     fail_if(error != NULL);
781     params = soup_form_encode("state", 
782                               gsignond_dictionary_get_string(data, "_Oauth2State"),
783                               "access_token", "meganewtoken",
784                               "token_type", "Bearer",
785                               NULL);
786     url = g_strdup_printf("http://somehost/login.html#%s", params);
787     gsignond_signonui_data_set_url_response(ui_data, url);
788     g_free(url);
789     g_free(params);
790     gsignond_plugin_user_action_finished(plugin, ui_data);
791     fail_if(result == NULL);
792     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
793                       "meganewtoken") != 0);
794     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
795                       "Bearer") != 0);
796     fail_if(gsignond_dictionary_get(result, "TokenParameters") == NULL);
797     fail_if(gsignond_dictionary_get(result, "Timestamp") == NULL);
798     fail_if(gsignond_dictionary_get(result, "Duration") != NULL);
799     fail_if(gsignond_dictionary_get(result, "Scope") == NULL);
800     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "") != 0);
801     fail_if(gsignond_dictionary_get(result, "RefreshToken") != NULL);
802     gsignond_dictionary_unref(result);
803     result = NULL;
804     fail_if(ui_action != NULL);
805     fail_if(store == NULL);
806     fail_if(g_hash_table_size(store) != 2);
807     client_tokens = gsignond_dictionary_new_from_variant(
808         gsignond_dictionary_get(store, "megaclient"));
809     token = gsignond_dictionary_new_from_variant(
810         gsignond_dictionary_get(client_tokens, ""));
811     fail_if(token == NULL);
812     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
813                       "meganewtoken") != 0);
814     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
815                       "Bearer") != 0);
816     fail_if(gsignond_dictionary_get(token, "TokenParameters") == NULL);
817     fail_if(gsignond_dictionary_get(token, "Timestamp") == NULL);
818     fail_if(gsignond_dictionary_get(token, "Duration") != NULL);
819     fail_if(gsignond_dictionary_get(token, "Scope") == NULL);
820     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "") != 0);
821     fail_if(gsignond_dictionary_get(token, "RefreshToken") != NULL);
822     
823     gsignond_dictionary_unref(token);
824     gsignond_dictionary_unref(client_tokens);
825
826     gsignond_dictionary_unref(store);
827     store = NULL;
828     fail_if(error != NULL);    
829     
830     
831     //return token and token type and all other parameters, with scope
832     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
833     //const gchar* scopes[] = { "scope1", "scope3", NULL };
834     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
835     
836     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
837     fail_if(result != NULL);
838     fail_if(ui_action == NULL);
839     gsignond_dictionary_unref(ui_action);
840     ui_action = NULL;
841     fail_if(store != NULL);
842     fail_if(error != NULL);
843     params = soup_form_encode("state", 
844                               gsignond_dictionary_get_string(data, "_Oauth2State"),
845                               "access_token", "meganewtoken",
846                               "token_type", "Bearer",
847                               "expires_in", "7200",
848                               "scope", "scope1 scope2 scope3",
849                               NULL);
850     url = g_strdup_printf("http://somehost/login.html#%s", params);
851     gsignond_signonui_data_set_url_response(ui_data, url);
852     g_free(url);
853     g_free(params);
854     gsignond_plugin_user_action_finished(plugin, ui_data);
855     fail_if(result == NULL);
856     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
857                       "meganewtoken") != 0);
858     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
859                       "Bearer") != 0);
860     fail_if(gsignond_dictionary_get(result, "TokenParameters") == NULL);
861     fail_if(gsignond_dictionary_get(result, "Timestamp") == NULL);
862     fail_if(gsignond_dictionary_get(result, "Duration") == NULL);
863     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
864     fail_if(gsignond_dictionary_get(result, "RefreshToken") != NULL);
865     gsignond_dictionary_unref(result);
866     result = NULL;
867     fail_if(ui_action != NULL);
868     fail_if(store == NULL);
869     fail_if(g_hash_table_size(store) != 2);
870     client_tokens = gsignond_dictionary_new_from_variant(
871         gsignond_dictionary_get(store, "megaclient"));
872     token = gsignond_dictionary_new_from_variant(
873         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
874     fail_if(token == NULL);
875     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
876                       "meganewtoken") != 0);
877     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
878                       "Bearer") != 0);
879     fail_if(gsignond_dictionary_get(token, "TokenParameters") == NULL);
880     fail_if(gsignond_dictionary_get(token, "Timestamp") == NULL);
881     fail_if(gsignond_dictionary_get(token, "Duration") == NULL);
882     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
883     fail_if(gsignond_dictionary_get(token, "RefreshToken") != NULL);
884     
885     gsignond_dictionary_unref(token);
886     gsignond_dictionary_unref(client_tokens);
887
888     gsignond_dictionary_unref(store);
889     store = NULL;
890     fail_if(error != NULL);
891     
892     //return token and token type and all other parameters, with 
893     //no requested scope
894     gsignond_dictionary_remove(tokens, "megaclient");    
895     gsignond_dictionary_remove(data, "Scope");
896     
897     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
898     fail_if(result != NULL);
899     fail_if(ui_action == NULL);
900     gsignond_dictionary_unref(ui_action);
901     ui_action = NULL;
902     fail_if(store != NULL);
903     fail_if(error != NULL);
904     params = soup_form_encode("state", 
905                               gsignond_dictionary_get_string(data, "_Oauth2State"),
906                               "access_token", "meganewtoken",
907                               "token_type", "Bearer",
908                               "expires_in", "7200",
909                               "scope", "scope1 scope2 scope3",
910                               NULL);
911     url = g_strdup_printf("http://somehost/login.html#%s", params);
912     gsignond_signonui_data_set_url_response(ui_data, url);
913     g_free(url);
914     g_free(params);
915     gsignond_plugin_user_action_finished(plugin, ui_data);
916     fail_if(result == NULL);
917     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
918                       "meganewtoken") != 0);
919     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
920                       "Bearer") != 0);
921     fail_if(gsignond_dictionary_get(result, "TokenParameters") == NULL);
922     fail_if(gsignond_dictionary_get(result, "Timestamp") == NULL);
923     fail_if(gsignond_dictionary_get(result, "Duration") == NULL);
924     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
925     fail_if(gsignond_dictionary_get(result, "RefreshToken") != NULL);
926     gsignond_dictionary_unref(result);
927     result = NULL;
928     fail_if(ui_action != NULL);
929     fail_if(store == NULL);
930     fail_if(g_hash_table_size(store) != 2);
931     client_tokens = gsignond_dictionary_new_from_variant(
932         gsignond_dictionary_get(store, "megaclient"));
933     token = gsignond_dictionary_new_from_variant(
934         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
935     fail_if(token == NULL);
936     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
937                       "meganewtoken") != 0);
938     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
939                       "Bearer") != 0);
940     fail_if(gsignond_dictionary_get(token, "TokenParameters") == NULL);
941     fail_if(gsignond_dictionary_get(token, "Timestamp") == NULL);
942     fail_if(gsignond_dictionary_get(token, "Duration") == NULL);
943     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
944     fail_if(gsignond_dictionary_get(token, "RefreshToken") != NULL);
945     
946     gsignond_dictionary_unref(token);
947     gsignond_dictionary_unref(client_tokens);
948
949     gsignond_dictionary_unref(store);
950     store = NULL;
951     fail_if(error != NULL);
952     
953     gsignond_dictionary_unref(ui_data);
954     gsignond_dictionary_unref(data);
955     gsignond_dictionary_unref(tokens);
956     g_object_unref(plugin);
957 }
958 END_TEST
959
960 static void
961 refresh_token_server_callback (SoupServer        *server,
962          SoupMessage       *msg, 
963          const char        *path,
964          GHashTable        *query,
965          SoupClientContext *client,
966          gpointer           user_data)
967 {
968     const gchar* normal_token_response = "{ \n\
969        \"access_token\":\"new-mega-token\",\n\
970        \"token_type\":\"Bearer\",\n\
971        \"expires_in\":1800,\n\
972        \"refresh_token\":\"new-refresh-token\",\n\
973        \"scope\":\"scope1 scope2 scope3\"\n\
974      }";
975      const gchar* invalid_grant_error = "{\n\
976        \"error\":\"invalid_grant\",\n\
977        \"error_description\":\"some description\",\n\
978        \"error_uri\":\"some uri\"\n\
979      }";
980      const gchar* generic_error = "{\n\
981        \"error\":\"invalid_request\",\n\
982        \"error_description\":\"some description\",\n\
983        \"error_uri\":\"some uri\"\n\
984      }";
985
986     fail_if(g_str_has_prefix (path, "/tokenpath") == FALSE);
987     fail_if(g_strcmp0(msg->method, "POST") != 0);
988     fail_if(g_strcmp0(soup_message_headers_get_content_type(
989          msg->request_headers, NULL), "application/x-www-form-urlencoded") != 0);
990      
991     SoupBuffer* request = soup_message_body_flatten(msg->request_body);
992     GHashTable* params = soup_form_decode(request->data);
993     soup_buffer_free(request);
994     fail_if(g_strcmp0(g_hash_table_lookup(params, "grant_type"), "refresh_token") != 0);
995     fail_if(g_strcmp0(g_hash_table_lookup(params, "refresh_token"), "megarefreshtoken") != 0);
996     fail_if(g_strcmp0(g_hash_table_lookup(params, "scope"), "scope1 scope3") != 0);        
997     g_hash_table_unref(params);
998
999     if (g_strrstr(path, "error/invalid_grant") != NULL) {
1000         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1001         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1002                                SOUP_MEMORY_STATIC,
1003                                invalid_grant_error, strlen(invalid_grant_error));
1004     } else if (g_strrstr(path, "error") != NULL) {
1005         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1006         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1007                                SOUP_MEMORY_STATIC,
1008                                generic_error, strlen(generic_error));
1009     } else {
1010         soup_message_set_status (msg, SOUP_STATUS_OK);
1011         soup_message_set_response (msg, "application/json;charset=UTF-8", 
1012                                SOUP_MEMORY_STATIC,
1013                                normal_token_response, strlen(normal_token_response));
1014     }
1015 }
1016
1017 START_TEST (test_oauth2_refresh)
1018 {
1019     // to genenerate cert and key
1020     // openssl genrsa -out privkey.pem 2048
1021     // openssl req -new -x509 -key privkey.pem -out cacert.pem -days 365000
1022     SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1023                                          SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1024                                          NULL);
1025     soup_server_add_handler (server, "/tokenpath", refresh_token_server_callback,
1026              NULL, NULL);
1027     soup_server_run_async(server);    
1028     
1029     gpointer plugin;
1030     
1031     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1032     fail_if(plugin == NULL);
1033
1034     GSignondSessionData* result = NULL;
1035     GSignondSessionData* store = NULL;
1036     GSignondSignonuiData* ui_action = NULL;
1037     GError* error = NULL;
1038     
1039     GSignondDictionary* token;
1040     GSignondDictionary* client_tokens;
1041
1042     
1043     //gsize len;
1044     gint64 expires_in;
1045
1046     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
1047     g_signal_connect(plugin, "user-action-required", 
1048                      G_CALLBACK(user_action_required_callback), &ui_action);
1049     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
1050     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
1051
1052     GSignondSessionData* data = gsignond_dictionary_new();
1053     GSignondDictionary* tokens = make_tokens("megaclient", 
1054                                                         make_expired_token());
1055
1056     // try using expired token
1057     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
1058     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
1059     gsignond_dictionary_set_string(data, "TokenHost", "localhost");
1060     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
1061     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
1062     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
1063     const gchar *realm_list[] = { "localhost", "somehost", NULL };
1064     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
1065     gsignond_session_data_set_allowed_realms(data, allowed_realms);
1066     g_sequence_free(allowed_realms);
1067     
1068     gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
1069     
1070     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1071     fail_if(result != NULL);    
1072     fail_if(ui_action != NULL);
1073     fail_if(store != NULL);
1074     fail_if(error != NULL);
1075
1076     while (1) {
1077         g_main_context_iteration(g_main_context_default(), TRUE);
1078         if(result != NULL)
1079             break;
1080     }
1081     fail_if(result == NULL);
1082     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
1083                       "new-mega-token") != 0);
1084     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "RefreshToken"),
1085                       "new-refresh-token") != 0);
1086     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
1087                       "Bearer") != 0);
1088     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
1089     fail_if(expires_in != 1800);
1090     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
1091     
1092     gsignond_dictionary_unref(result);
1093     result = NULL;
1094     fail_if(ui_action != NULL);
1095     fail_if(store == NULL);
1096     client_tokens = gsignond_dictionary_new_from_variant(
1097         gsignond_dictionary_get(store, "megaclient"));
1098     token = gsignond_dictionary_new_from_variant(
1099         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
1100     fail_if(token == NULL);
1101     
1102     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
1103                       "new-mega-token") != 0);
1104     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "RefreshToken"),
1105                       "new-refresh-token") != 0);
1106     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
1107                       "Bearer") != 0);
1108     fail_if(gsignond_dictionary_get_int64(token, "Duration", &expires_in) != TRUE);
1109     fail_if(expires_in != 1800);
1110     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
1111     
1112     
1113     gsignond_dictionary_unref(token);
1114     gsignond_dictionary_unref(client_tokens);
1115
1116     gsignond_dictionary_unref(store);
1117     store = NULL;
1118     fail_if(error != NULL);
1119
1120     //try with incorrect http port
1121     gsignond_dictionary_unref(tokens);
1122     tokens = make_tokens("megaclient", make_expired_token());
1123     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server) + 1);
1124     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1125     fail_if(result != NULL);    
1126     fail_if(ui_action != NULL);
1127     fail_if(store != NULL);
1128     fail_if(error != NULL);
1129
1130     while (1) {
1131         g_main_context_iteration(g_main_context_default(), TRUE);
1132         if(error != NULL)
1133             break;
1134     }
1135     fail_if(result != NULL);    
1136     fail_if(ui_action != NULL);
1137     fail_if(store != NULL);
1138     fail_if(error == NULL);
1139     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
1140                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
1141     fail_if(g_str_has_prefix(error->message, 
1142                              "Token endpoint returned an error") == FALSE);
1143     g_error_free(error);
1144     error = NULL;
1145     
1146     // try with generic error
1147     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
1148     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath/error");
1149     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1150     fail_if(result != NULL);    
1151     fail_if(ui_action != NULL);
1152     fail_if(store != NULL);
1153     fail_if(error != NULL);
1154
1155     while (1) {
1156         g_main_context_iteration(g_main_context_default(), TRUE);
1157         if(error != NULL)
1158             break;
1159     }
1160     fail_if(result != NULL);    
1161     fail_if(ui_action != NULL);
1162     fail_if(store != NULL);
1163     fail_if(error == NULL);
1164     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
1165                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
1166     fail_if(g_str_has_prefix(error->message, 
1167                              "Authorization server returned an error") == FALSE);
1168     g_error_free(error);
1169     error = NULL;
1170     
1171     //try with invalid grant error, should get a ui request
1172     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath/error/invalid_grant");
1173     gsignond_dictionary_set_string(data, "ResponseType", "code");
1174     gsignond_dictionary_set_string(data, "AuthHost", "somehost");
1175     gsignond_dictionary_set_string(data, "AuthPath", "/somepath");
1176     
1177     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1178     fail_if(result != NULL);    
1179     fail_if(ui_action != NULL);
1180     fail_if(store != NULL);
1181     fail_if(error != NULL);
1182
1183     while (1) {
1184         g_main_context_iteration(g_main_context_default(), TRUE);
1185         if(ui_action != NULL)
1186             break;
1187     }
1188     fail_if(result != NULL);    
1189     fail_if(ui_action == NULL);
1190     
1191     gsignond_dictionary_unref(ui_action);
1192     ui_action = NULL;
1193     fail_if(store != NULL);
1194     fail_if(error != NULL);
1195
1196     //the following two cases are for testing forcing the use of refresh token
1197     //first check that without forcing the use a token from cache is returned
1198     gsignond_dictionary_unref(tokens);
1199     tokens = make_tokens("megaclient", make_normal_token());
1200     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
1201     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1202     fail_if(result == NULL);    
1203     gsignond_dictionary_unref(result);
1204     result = NULL;
1205     fail_if(ui_action != NULL);
1206     fail_if(store != NULL);
1207     fail_if(error != NULL);
1208    
1209     //now force the use of refresh token
1210     gsignond_dictionary_set_boolean(data, "ForceTokenRefresh", TRUE);
1211     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1212     fail_if(result != NULL);    
1213     fail_if(ui_action != NULL);
1214     fail_if(store != NULL);
1215     fail_if(error != NULL);
1216
1217     while (1) {
1218         g_main_context_iteration(g_main_context_default(), TRUE);
1219         if(result != NULL)
1220             break;
1221     }
1222     fail_if(result == NULL);
1223     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
1224                       "new-mega-token") != 0);
1225     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "RefreshToken"),
1226                       "new-refresh-token") != 0);
1227     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
1228                       "Bearer") != 0);
1229     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
1230     fail_if(expires_in != 1800);
1231     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
1232     
1233     gsignond_dictionary_unref(result);
1234     result = NULL;
1235     fail_if(ui_action != NULL);
1236     fail_if(store == NULL);
1237     client_tokens = gsignond_dictionary_new_from_variant(
1238         gsignond_dictionary_get(store, "megaclient"));
1239     token = gsignond_dictionary_new_from_variant(
1240         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
1241     fail_if(token == NULL);
1242     
1243     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
1244                       "new-mega-token") != 0);
1245     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "RefreshToken"),
1246                       "new-refresh-token") != 0);
1247     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
1248                       "Bearer") != 0);
1249     fail_if(gsignond_dictionary_get_int64(token, "Duration", &expires_in) != TRUE);
1250     fail_if(expires_in != 1800);
1251     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
1252     gsignond_dictionary_unref(token);
1253     gsignond_dictionary_unref(client_tokens);
1254
1255     gsignond_dictionary_unref(store);
1256     store = NULL;
1257     fail_if(error != NULL);
1258    
1259     gsignond_dictionary_unref(data);
1260     gsignond_dictionary_unref(tokens);
1261     g_object_unref(plugin);
1262     g_object_unref(server);
1263 }
1264 END_TEST
1265
1266 static gboolean
1267 client_auth_callback (SoupAuthDomain *domain, SoupMessage *msg,
1268            const char *username, const char *password,
1269            gpointer user_data)
1270 {
1271     return (g_strcmp0 (password, "megapassword") == 0 &&
1272             g_strcmp0 (username, "megaclient") == 0);
1273 }
1274
1275 START_TEST (test_oauth2_client_basic_auth)
1276 {
1277     SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1278                                          SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1279                                          NULL);
1280     SoupAuthDomain *domain = soup_auth_domain_basic_new (
1281         SOUP_AUTH_DOMAIN_REALM, "My Realm",
1282         SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, client_auth_callback,
1283         SOUP_AUTH_DOMAIN_ADD_PATH, "/tokenpath",
1284         NULL);
1285     soup_server_add_auth_domain (server, domain);
1286     g_object_unref (domain);    
1287     soup_server_add_handler (server, "/tokenpath", refresh_token_server_callback,
1288              NULL, NULL);
1289     soup_server_run_async(server);    
1290     
1291     gpointer plugin;
1292     
1293     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1294     fail_if(plugin == NULL);
1295
1296     GSignondSessionData* result = NULL;
1297     GSignondSessionData* store = NULL;
1298     GSignondSignonuiData* ui_action = NULL;
1299     GError* error = NULL;
1300     
1301     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
1302     g_signal_connect(plugin, "user-action-required", 
1303                      G_CALLBACK(user_action_required_callback), &ui_action);
1304     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
1305     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
1306
1307     GSignondSessionData* data = gsignond_dictionary_new();
1308     GSignondDictionary* tokens = make_tokens("megaclient", 
1309                                                         make_expired_token());
1310
1311     //try with client authorization using absent client credentials
1312     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
1313     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
1314     gsignond_dictionary_set_string(data, "TokenHost", "localhost");
1315     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
1316     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
1317     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
1318     
1319     gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
1320
1321     const gchar *realm_list[] = { "localhost", NULL };
1322     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
1323     gsignond_session_data_set_allowed_realms(data, allowed_realms);
1324     g_sequence_free(allowed_realms);
1325     
1326     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1327     fail_if(result != NULL);    
1328     fail_if(ui_action != NULL);
1329     fail_if(store != NULL);
1330     fail_if(error != NULL);
1331
1332     while (1) {
1333         g_main_context_iteration(g_main_context_default(), TRUE);
1334         if(error != NULL)
1335             break;
1336     }
1337     fail_if(result != NULL);
1338     fail_if(ui_action != NULL);
1339     fail_if(store != NULL);
1340     fail_if(error == NULL);
1341     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
1342                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
1343     fail_if(g_str_has_prefix(error->message, 
1344                              "Token endpoint returned an error") == FALSE);
1345     g_error_free(error);
1346     error = NULL;
1347
1348     //try with client authorization using incorrect client credentials
1349     gsignond_dictionary_set_string(data, "ClientSecret", "incorrectpassword");
1350     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1351     fail_if(result != NULL);    
1352     fail_if(ui_action != NULL);
1353     fail_if(store != NULL);
1354     fail_if(error != NULL);
1355
1356     while (1) {
1357         g_main_context_iteration(g_main_context_default(), TRUE);
1358         if(error != NULL)
1359             break;
1360     }
1361     fail_if(result != NULL);
1362     fail_if(ui_action != NULL);
1363     fail_if(store != NULL);
1364     fail_if(error == NULL);
1365     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
1366                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
1367     fail_if(g_str_has_prefix(error->message, 
1368                              "Token endpoint returned an error") == FALSE);
1369     g_error_free(error);
1370     error = NULL;
1371
1372     //try with ForceClientAuthViaRequestBody set to TRUE
1373     gsignond_dictionary_set_boolean(data, "ForceClientAuthViaRequestBody", TRUE);
1374     gsignond_dictionary_set_string(data, "ClientSecret", "megapassword");
1375     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1376     fail_if(result != NULL);    
1377     fail_if(ui_action != NULL);
1378     fail_if(store != NULL);
1379     fail_if(error != NULL);
1380
1381     while (1) {
1382         g_main_context_iteration(g_main_context_default(), TRUE);
1383         if(error != NULL)
1384             break;
1385     }
1386     fail_if(result != NULL);
1387     fail_if(ui_action != NULL);
1388     fail_if(store != NULL);
1389     fail_if(error == NULL);
1390     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
1391                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
1392     fail_if(g_str_has_prefix(error->message, 
1393                              "Token endpoint returned an error") == FALSE);
1394     g_error_free(error);
1395     error = NULL;
1396
1397     
1398     //try with client authorization using correct client credentials
1399     gsignond_dictionary_set_boolean(data, "ForceClientAuthViaRequestBody", FALSE);
1400     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1401     fail_if(result != NULL);    
1402     fail_if(ui_action != NULL);
1403     fail_if(store != NULL);
1404     fail_if(error != NULL);
1405
1406     while (1) {
1407         g_main_context_iteration(g_main_context_default(), TRUE);
1408         if(result != NULL)
1409             break;
1410     }
1411     fail_if(result == NULL);
1412     gsignond_dictionary_unref(result);
1413     result = NULL;
1414     fail_if(ui_action != NULL);
1415     fail_if(store == NULL);
1416     gsignond_dictionary_unref(store);
1417     store = NULL;
1418     fail_if(error != NULL);
1419     
1420     gsignond_dictionary_unref(data);
1421     gsignond_dictionary_unref(tokens);
1422     g_object_unref(plugin);
1423     g_object_unref(server);
1424 }
1425 END_TEST
1426
1427
1428 static void
1429 request_body_auth_server_callback (SoupServer        *server,
1430          SoupMessage       *msg, 
1431          const char        *path,
1432          GHashTable        *query,
1433          SoupClientContext *client,
1434          gpointer           user_data)
1435 {
1436     const gchar* normal_token_response = "{ \n\
1437        \"access_token\":\"new-mega-token\",\n\
1438        \"token_type\":\"Bearer\",\n\
1439        \"expires_in\":1800,\n\
1440        \"refresh_token\":\"new-refresh-token\",\n\
1441        \"scope\":\"scope1 scope2 scope3\"\n\
1442      }";
1443      const gchar* invalid_grant_error = "{\n\
1444        \"error\":\"invalid_grant\",\n\
1445        \"error_description\":\"some description\",\n\
1446        \"error_uri\":\"some uri\"\n\
1447      }";
1448      const gchar* generic_error = "{\n\
1449        \"error\":\"invalid_request\",\n\
1450        \"error_description\":\"some description\",\n\
1451        \"error_uri\":\"some uri\"\n\
1452      }";
1453
1454     fail_if(g_str_has_prefix (path, "/tokenpath") == FALSE);
1455     fail_if(g_strcmp0(msg->method, "POST") != 0);
1456     fail_if(g_strcmp0(soup_message_headers_get_content_type(
1457          msg->request_headers, NULL), "application/x-www-form-urlencoded") != 0);
1458      
1459     SoupBuffer* request = soup_message_body_flatten(msg->request_body);
1460     GHashTable* params = soup_form_decode(request->data);
1461     soup_buffer_free(request);
1462     fail_if(g_strcmp0(g_hash_table_lookup(params, "grant_type"), "refresh_token") != 0);
1463     fail_if(g_strcmp0(g_hash_table_lookup(params, "refresh_token"), "megarefreshtoken") != 0);
1464     fail_if(g_strcmp0(g_hash_table_lookup(params, "scope"), "scope1 scope3") != 0);
1465     
1466     gboolean auth_error = FALSE;
1467     if (g_strcmp0(g_hash_table_lookup(params, "client_id"), "megaclient") != 0 ||
1468         g_strcmp0(g_hash_table_lookup(params, "client_secret"), "megapassword") != 0) {
1469             auth_error = TRUE;
1470     }
1471     g_hash_table_unref(params);
1472
1473     if (g_strrstr(path, "error/invalid_grant") != NULL) {
1474         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1475         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1476                                SOUP_MEMORY_STATIC,
1477                                invalid_grant_error, strlen(invalid_grant_error));
1478     } else if (g_strrstr(path, "error") != NULL || auth_error == TRUE) {
1479         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1480         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1481                                SOUP_MEMORY_STATIC,
1482                                generic_error, strlen(generic_error));
1483     } else {
1484         soup_message_set_status (msg, SOUP_STATUS_OK);
1485         soup_message_set_response (msg, "application/json;charset=UTF-8", 
1486                                SOUP_MEMORY_STATIC,
1487                                normal_token_response, strlen(normal_token_response));
1488     }
1489 }
1490
1491
1492 START_TEST (test_oauth2_client_request_body_auth)
1493 {
1494     SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1495                                          SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1496                                          NULL);
1497     soup_server_add_handler (server, "/tokenpath", request_body_auth_server_callback,
1498              NULL, NULL);
1499     soup_server_run_async(server);    
1500     
1501     gpointer plugin;
1502     
1503     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1504     fail_if(plugin == NULL);
1505
1506     GSignondSessionData* result = NULL;
1507     GSignondSessionData* store = NULL;
1508     GSignondSignonuiData* ui_action = NULL;
1509     GError* error = NULL;
1510     
1511     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
1512     g_signal_connect(plugin, "user-action-required", 
1513                      G_CALLBACK(user_action_required_callback), &ui_action);
1514     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
1515     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
1516
1517     GSignondSessionData* data = gsignond_dictionary_new();
1518     GSignondDictionary* tokens = make_tokens("megaclient", 
1519                                                         make_expired_token());
1520
1521     //try with client authorization using absent ForceClientAuthViaRequestBody
1522     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
1523     gsignond_dictionary_set_string(data, "ClientSecret", "megapassword");
1524     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
1525     gsignond_dictionary_set_string(data, "TokenHost", "localhost");
1526     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
1527     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
1528     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
1529     
1530     gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
1531
1532     const gchar *realm_list[] = { "localhost", NULL };
1533     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
1534     gsignond_session_data_set_allowed_realms(data, allowed_realms);
1535     g_sequence_free(allowed_realms);
1536     
1537     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1538     fail_if(result != NULL);    
1539     fail_if(ui_action != NULL);
1540     fail_if(store != NULL);
1541     fail_if(error != NULL);
1542
1543     while (1) {
1544         g_main_context_iteration(g_main_context_default(), TRUE);
1545         if(error != NULL)
1546             break;
1547     }
1548     fail_if(result != NULL);
1549     fail_if(ui_action != NULL);
1550     fail_if(store != NULL);
1551     fail_if(error == NULL);
1552     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
1553                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
1554     fail_if(g_str_has_prefix(error->message, 
1555                              "Authorization server returned an error") == FALSE);
1556     g_error_free(error);
1557     error = NULL;
1558
1559     //try with ForceClientAuthViaRequestBody set to TRUE
1560     gsignond_dictionary_set_boolean(data, "ForceClientAuthViaRequestBody", TRUE);
1561     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1562     fail_if(result != NULL);    
1563     fail_if(ui_action != NULL);
1564     fail_if(store != NULL);
1565     fail_if(error != NULL);
1566
1567     while (1) {
1568         g_main_context_iteration(g_main_context_default(), TRUE);
1569         if(result != NULL)
1570             break;
1571     }
1572     fail_if(result == NULL);
1573     gsignond_dictionary_unref(result);
1574     result = NULL;
1575     fail_if(ui_action != NULL);
1576     fail_if(store == NULL);
1577     gsignond_dictionary_unref(store);
1578     store = NULL;
1579     fail_if(error != NULL);
1580     
1581     gsignond_dictionary_unref(data);
1582     gsignond_dictionary_unref(tokens);
1583     g_object_unref(plugin);
1584     g_object_unref(server);
1585 }
1586 END_TEST
1587
1588
1589 static void
1590 password_token_server_callback (SoupServer        *server,
1591          SoupMessage       *msg, 
1592          const char        *path,
1593          GHashTable        *query,
1594          SoupClientContext *client,
1595          gpointer           user_data)
1596 {
1597     const gchar* normal_token_response = "{ \n\
1598        \"access_token\":\"new-mega-token\",\n\
1599        \"token_type\":\"Bearer\",\n\
1600        \"expires_in\":1800,\n\
1601        \"refresh_token\":\"new-refresh-token\",\n\
1602        \"scope\":\"scope1 scope2 scope3\"\n\
1603      }";
1604      const gchar* invalid_grant_error = "{\n\
1605        \"error\":\"invalid_grant\",\n\
1606        \"error_description\":\"some description\",\n\
1607        \"error_uri\":\"some uri\"\n\
1608      }";
1609      const gchar* generic_error = "{\n\
1610        \"error\":\"invalid_request\",\n\
1611        \"error_description\":\"some description\",\n\
1612        \"error_uri\":\"some uri\"\n\
1613      }";
1614
1615     fail_if(g_str_has_prefix (path, "/tokenpath") == FALSE);
1616     fail_if(g_strcmp0(msg->method, "POST") != 0);
1617     fail_if(g_strcmp0(soup_message_headers_get_content_type(
1618          msg->request_headers, NULL), "application/x-www-form-urlencoded") != 0);
1619      
1620     SoupBuffer* request = soup_message_body_flatten(msg->request_body);
1621     GHashTable* params = soup_form_decode(request->data);
1622     soup_buffer_free(request);
1623     fail_if(g_strcmp0(g_hash_table_lookup(params, "grant_type"), "password") != 0);
1624     fail_if(g_strcmp0(g_hash_table_lookup(params, "username"), "megauser") != 0);
1625     fail_if(g_strcmp0(g_hash_table_lookup(params, "password"), "megapassword") != 0);
1626     fail_if(g_strcmp0(g_hash_table_lookup(params, "scope"), "scope1 scope3") != 0);        
1627     g_hash_table_unref(params);
1628
1629     if (g_strrstr(path, "error/invalid_grant") != NULL) {
1630         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1631         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1632                                SOUP_MEMORY_STATIC,
1633                                invalid_grant_error, strlen(invalid_grant_error));
1634     } else if (g_strrstr(path, "error") != NULL) {
1635         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1636         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1637                                SOUP_MEMORY_STATIC,
1638                                generic_error, strlen(generic_error));
1639     } else {
1640         soup_message_set_status (msg, SOUP_STATUS_OK);
1641         soup_message_set_response (msg, "application/json;charset=UTF-8", 
1642                                SOUP_MEMORY_STATIC,
1643                                normal_token_response, strlen(normal_token_response));
1644     }
1645 }
1646
1647 START_TEST (test_oauth2_owner_password)
1648 {
1649     SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1650                                          SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1651                                          NULL);
1652     soup_server_add_handler (server, "/tokenpath", password_token_server_callback,
1653              NULL, NULL);
1654     soup_server_run_async(server);    
1655     
1656     gpointer plugin;
1657     
1658     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1659     fail_if(plugin == NULL);
1660
1661     GSignondSessionData* result = NULL;
1662     GSignondSessionData* store = NULL;
1663     GSignondSignonuiData* ui_action = NULL;
1664     GError* error = NULL;
1665     
1666     //gsize len;
1667     gint64 expires_in;
1668
1669     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
1670     g_signal_connect(plugin, "user-action-required", 
1671                      G_CALLBACK(user_action_required_callback), &ui_action);
1672     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
1673     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
1674
1675     GSignondSessionData* data = gsignond_dictionary_new();
1676     GSignondDictionary* tokens = make_tokens("someclient", 
1677                                                         make_expired_token());
1678
1679     // try a default scenario
1680     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
1681     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
1682     gsignond_dictionary_set_string(data, "TokenHost", "localhost");
1683     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
1684     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
1685     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
1686     
1687     gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
1688
1689     const gchar *realm_list[] = { "localhost", NULL };
1690     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
1691     gsignond_session_data_set_allowed_realms(data, allowed_realms);
1692     g_sequence_free(allowed_realms);
1693
1694     gsignond_dictionary_set_string(data, "GrantType", "password");
1695     gsignond_session_data_set_username(data, "megauser");
1696     gsignond_session_data_set_secret(data, "megapassword");    
1697     
1698     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1699     fail_if(result != NULL);    
1700     fail_if(ui_action != NULL);
1701     fail_if(store != NULL);
1702     fail_if(error != NULL);
1703
1704     while (1) {
1705         g_main_context_iteration(g_main_context_default(), TRUE);
1706         if(result != NULL)
1707             break;
1708     }
1709     fail_if(result == NULL);
1710     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
1711                       "new-mega-token") != 0);
1712     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "RefreshToken"),
1713                       "new-refresh-token") != 0);
1714     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
1715                       "Bearer") != 0);
1716     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
1717     fail_if(expires_in != 1800);
1718     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
1719     
1720     gsignond_dictionary_unref(result);
1721     result = NULL;
1722     fail_if(ui_action != NULL);
1723     fail_if(store == NULL);
1724     GSignondDictionary* client_tokens = gsignond_dictionary_new_from_variant(
1725         gsignond_dictionary_get(store, "megaclient"));
1726     GSignondDictionary* token = gsignond_dictionary_new_from_variant(
1727         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
1728     fail_if(token == NULL);
1729     
1730     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
1731                       "new-mega-token") != 0);
1732     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "RefreshToken"),
1733                       "new-refresh-token") != 0);
1734     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
1735                       "Bearer") != 0);
1736     fail_if(gsignond_dictionary_get_int64(token, "Duration", &expires_in) != TRUE);
1737     fail_if(expires_in != 1800);
1738     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
1739     
1740     gsignond_dictionary_unref(token);
1741     gsignond_dictionary_unref(client_tokens);
1742
1743     gsignond_dictionary_unref(store);
1744     store = NULL;
1745     fail_if(error != NULL);
1746
1747     gsignond_dictionary_unref(data);
1748     gsignond_dictionary_unref(tokens);
1749     g_object_unref(plugin);
1750     g_object_unref(server);
1751 }
1752 END_TEST
1753
1754 static void
1755 client_credentials_token_server_callback (SoupServer        *server,
1756          SoupMessage       *msg, 
1757          const char        *path,
1758          GHashTable        *query,
1759          SoupClientContext *client,
1760          gpointer           user_data)
1761 {
1762     const gchar* normal_token_response = "{ \n\
1763        \"access_token\":\"new-mega-token\",\n\
1764        \"token_type\":\"Bearer\",\n\
1765        \"expires_in\":1800,\n\
1766        \"refresh_token\":\"new-refresh-token\",\n\
1767        \"scope\":\"scope1 scope2 scope3\"\n\
1768      }";
1769      const gchar* invalid_grant_error = "{\n\
1770        \"error\":\"invalid_grant\",\n\
1771        \"error_description\":\"some description\",\n\
1772        \"error_uri\":\"some uri\"\n\
1773      }";
1774      const gchar* generic_error = "{\n\
1775        \"error\":\"invalid_request\",\n\
1776        \"error_description\":\"some description\",\n\
1777        \"error_uri\":\"some uri\"\n\
1778      }";
1779
1780     fail_if(g_str_has_prefix (path, "/tokenpath") == FALSE);
1781     fail_if(g_strcmp0(msg->method, "POST") != 0);
1782     fail_if(g_strcmp0(soup_message_headers_get_content_type(
1783          msg->request_headers, NULL), "application/x-www-form-urlencoded") != 0);
1784      
1785     SoupBuffer* request = soup_message_body_flatten(msg->request_body);
1786     GHashTable* params = soup_form_decode(request->data);
1787     soup_buffer_free(request);
1788     fail_if(g_strcmp0(g_hash_table_lookup(params, "grant_type"), "client_credentials") != 0);
1789     fail_if(g_strcmp0(g_hash_table_lookup(params, "scope"), "scope1 scope3") != 0);        
1790     g_hash_table_unref(params);
1791
1792     if (g_strrstr(path, "error/invalid_grant") != NULL) {
1793         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1794         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1795                                SOUP_MEMORY_STATIC,
1796                                invalid_grant_error, strlen(invalid_grant_error));
1797     } else if (g_strrstr(path, "error") != NULL) {
1798         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1799         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1800                                SOUP_MEMORY_STATIC,
1801                                generic_error, strlen(generic_error));
1802     } else {
1803         soup_message_set_status (msg, SOUP_STATUS_OK);
1804         soup_message_set_response (msg, "application/json;charset=UTF-8", 
1805                                SOUP_MEMORY_STATIC,
1806                                normal_token_response, strlen(normal_token_response));
1807     }
1808 }
1809
1810 START_TEST (test_oauth2_client_credentials)
1811 {
1812     SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1813                                          SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1814                                          NULL);
1815     soup_server_add_handler (server, "/tokenpath", client_credentials_token_server_callback,
1816              NULL, NULL);
1817     soup_server_run_async(server);    
1818     
1819     gpointer plugin;
1820     
1821     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1822     fail_if(plugin == NULL);
1823
1824     GSignondSessionData* result = NULL;
1825     GSignondSessionData* store = NULL;
1826     GSignondSignonuiData* ui_action = NULL;
1827     GError* error = NULL;
1828     
1829     //gsize len;
1830     gint64 expires_in;
1831
1832     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
1833     g_signal_connect(plugin, "user-action-required", 
1834                      G_CALLBACK(user_action_required_callback), &ui_action);
1835     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
1836     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
1837
1838     GSignondSessionData* data = gsignond_dictionary_new();
1839     GSignondDictionary* tokens = make_tokens("someclient", 
1840                                                         make_expired_token());
1841
1842     // try a default scenario
1843     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
1844     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
1845     gsignond_dictionary_set_string(data, "TokenHost", "localhost");
1846     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
1847     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
1848     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
1849     const gchar *realm_list[] = { "localhost", NULL };
1850     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
1851     gsignond_session_data_set_allowed_realms(data, allowed_realms);
1852     g_sequence_free(allowed_realms);
1853     
1854     gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
1855
1856     gsignond_dictionary_set_string(data, "GrantType", "client_credentials");
1857     
1858     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
1859     fail_if(result != NULL);    
1860     fail_if(ui_action != NULL);
1861     fail_if(store != NULL);
1862     fail_if(error != NULL);
1863
1864     while (1) {
1865         g_main_context_iteration(g_main_context_default(), TRUE);
1866         if(result != NULL)
1867             break;
1868     }
1869     fail_if(result == NULL);
1870     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
1871                       "new-mega-token") != 0);
1872     // client credentials grant isn't eligible for refresh tokens (see RFC6749)
1873     fail_if(gsignond_dictionary_get_string(result, "RefreshToken") != NULL);
1874     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
1875                       "Bearer") != 0);
1876     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
1877     fail_if(expires_in != 1800);
1878     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
1879     
1880     gsignond_dictionary_unref(result);
1881     result = NULL;
1882     fail_if(ui_action != NULL);
1883     fail_if(store == NULL);
1884     GSignondDictionary* client_tokens = gsignond_dictionary_new_from_variant(
1885         gsignond_dictionary_get(store, "megaclient"));
1886     GSignondDictionary* token = gsignond_dictionary_new_from_variant(
1887         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
1888     fail_if(token == NULL);
1889     
1890     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
1891                       "new-mega-token") != 0);
1892     fail_if(gsignond_dictionary_get_string(token, "RefreshToken") != NULL);
1893     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
1894                       "Bearer") != 0);
1895     fail_if(gsignond_dictionary_get_int64(token, "Duration", &expires_in) != TRUE);
1896     fail_if(expires_in != 1800);
1897     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
1898     
1899     gsignond_dictionary_unref(token);
1900     gsignond_dictionary_unref(client_tokens);
1901
1902     gsignond_dictionary_unref(store);
1903     store = NULL;
1904     fail_if(error != NULL);
1905
1906     gsignond_dictionary_unref(data);
1907     gsignond_dictionary_unref(tokens);
1908     g_object_unref(plugin);
1909     g_object_unref(server);
1910 }
1911 END_TEST
1912
1913 static void
1914 authorization_code_token_server_callback (SoupServer        *server,
1915          SoupMessage       *msg, 
1916          const char        *path,
1917          GHashTable        *query,
1918          SoupClientContext *client,
1919          gpointer           user_data)
1920 {
1921     const gchar* normal_token_response = "{ \n\
1922        \"access_token\":\"new-mega-token\",\n\
1923        \"token_type\":\"Bearer\",\n\
1924        \"expires_in\":1800,\n\
1925        \"refresh_token\":\"new-refresh-token\",\n\
1926        \"scope\":\"scope1 scope2 scope3\"\n\
1927      }";
1928      const gchar* invalid_grant_error = "{\n\
1929        \"error\":\"invalid_grant\",\n\
1930        \"error_description\":\"some description\",\n\
1931        \"error_uri\":\"some uri\"\n\
1932      }";
1933      const gchar* generic_error = "{\n\
1934        \"error\":\"invalid_request\",\n\
1935        \"error_description\":\"some description\",\n\
1936        \"error_uri\":\"some uri\"\n\
1937      }";
1938
1939     fail_if(g_str_has_prefix (path, "/tokenpath") == FALSE);
1940     fail_if(g_strcmp0(msg->method, "POST") != 0);
1941     fail_if(g_strcmp0(soup_message_headers_get_content_type(
1942          msg->request_headers, NULL), "application/x-www-form-urlencoded") != 0);
1943      
1944     SoupBuffer* request = soup_message_body_flatten(msg->request_body);
1945     GHashTable* params = soup_form_decode(request->data);
1946     soup_buffer_free(request);
1947     fail_if(g_strcmp0(g_hash_table_lookup(params, "grant_type"), "authorization_code") != 0);
1948     fail_if(g_strcmp0(g_hash_table_lookup(params, "code"), "mega-auth-code") != 0);
1949     fail_if(g_strcmp0(g_hash_table_lookup(params, "redirect_uri"), "http://somehost/login.html") != 0);
1950     fail_if(g_strcmp0(g_hash_table_lookup(params, "client_id"), "megaclient") != 0);        
1951     g_hash_table_unref(params);
1952
1953     if (g_strrstr(path, "error/invalid_grant") != NULL) {
1954         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1955         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1956                                SOUP_MEMORY_STATIC,
1957                                invalid_grant_error, strlen(invalid_grant_error));
1958     } else if (g_strrstr(path, "error") != NULL) {
1959         soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST);
1960         soup_message_set_response(msg, "application/json;charset=UTF-8", 
1961                                SOUP_MEMORY_STATIC,
1962                                generic_error, strlen(generic_error));
1963     } else {
1964         soup_message_set_status (msg, SOUP_STATUS_OK);
1965         soup_message_set_response (msg, "application/json;charset=UTF-8", 
1966                                SOUP_MEMORY_STATIC,
1967                                normal_token_response, strlen(normal_token_response));
1968     }
1969 }
1970
1971 START_TEST (test_oauth2_authorization_code)
1972 {
1973     SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1974                                          SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1975                                          NULL);
1976     soup_server_add_handler (server, "/tokenpath", authorization_code_token_server_callback,
1977              NULL, NULL);
1978     soup_server_run_async(server);    
1979     
1980     gpointer plugin;
1981     
1982     plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1983     fail_if(plugin == NULL);
1984
1985     GSignondSessionData* result = NULL;
1986     GSignondSessionData* store = NULL;
1987     GSignondSignonuiData* ui_action = NULL;
1988     GError* error = NULL;
1989     
1990     //gsize len;
1991     gint64 expires_in;
1992     gchar* url;
1993     gchar* params;    
1994
1995     g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result);
1996     g_signal_connect(plugin, "user-action-required", 
1997                      G_CALLBACK(user_action_required_callback), &ui_action);
1998     g_signal_connect(plugin, "store", G_CALLBACK(store_callback), &store);
1999     g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);
2000
2001     GSignondSessionData* data = gsignond_dictionary_new();
2002     GSignondDictionary* tokens = make_tokens("someclient", make_expired_token());
2003     GSignondSignonuiData* ui_data = gsignond_dictionary_new();
2004     
2005     gsignond_dictionary_set_string(data, "ClientId", "megaclient");
2006     gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
2007     gsignond_dictionary_set_string(data, "TokenHost", "localhost");
2008     gsignond_dictionary_set_string(data, "TokenPath", "/tokenpath");
2009     gsignond_dictionary_set_uint32(data, "TokenPort", soup_server_get_port(server));
2010     gsignond_dictionary_set_string(data, "Scope", "scope1 scope3");
2011     
2012     gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
2013
2014     gsignond_dictionary_set_string(data, "AuthHost", "somehost");
2015     gsignond_dictionary_set_string(data, "AuthPath", "/somepath");
2016     gsignond_dictionary_set_string(data, "ResponseType", "code");
2017     gsignond_dictionary_set_string(data, "RedirectUri", "http://somehost/login.html");
2018     const gchar *realm_list[] = { "localhost", "somehost", NULL };
2019     GSequence* allowed_realms = gsignond_copy_array_to_sequence(realm_list);
2020     gsignond_session_data_set_allowed_realms(data, allowed_realms);
2021     g_sequence_free(allowed_realms);
2022
2023     //authentication code is absent
2024     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
2025     fail_if(result != NULL);
2026     fail_if(ui_action == NULL);
2027     gsignond_dictionary_unref(ui_action);
2028     ui_action = NULL;
2029     fail_if(store != NULL);
2030     fail_if(error != NULL);  
2031
2032     params = soup_form_encode("state", 
2033                               gsignond_dictionary_get_string(data, "_Oauth2State"),
2034                               NULL);
2035     url = g_strdup_printf("http://somehost/login.html?%s", params);
2036     gsignond_signonui_data_set_url_response(ui_data, url);
2037     g_free(url);
2038     g_free(params);
2039     gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_NONE);
2040     gsignond_plugin_user_action_finished(plugin, ui_data);
2041     fail_if(result != NULL);
2042     fail_if(ui_action != NULL);
2043     fail_if(store != NULL);
2044     fail_if(error == NULL);
2045     fail_unless(g_error_matches(error, GSIGNOND_ERROR, 
2046                                 GSIGNOND_ERROR_NOT_AUTHORIZED));
2047     fail_if(g_str_has_prefix(error->message, "Authorization endpoint didn't issue an\
2048  authorization code") == FALSE);
2049     g_error_free(error);
2050     error = NULL;
2051
2052     //authentication code is present 
2053     gsignond_plugin_request_initial(plugin, data, tokens, "oauth2");
2054     fail_if(result != NULL);
2055     fail_if(ui_action == NULL);
2056     gsignond_dictionary_unref(ui_action);
2057     ui_action = NULL;
2058     fail_if(store != NULL);
2059     fail_if(error != NULL);  
2060
2061     params = soup_form_encode("state", 
2062                               gsignond_dictionary_get_string(data, "_Oauth2State"),
2063                               "code", "mega-auth-code",
2064                               NULL);
2065     url = g_strdup_printf("http://somehost/login.html?%s", params);
2066     gsignond_signonui_data_set_url_response(ui_data, url);
2067     g_free(url);
2068     g_free(params);
2069     gsignond_plugin_user_action_finished(plugin, ui_data);
2070
2071     while (1) {
2072         g_main_context_iteration(g_main_context_default(), TRUE);
2073         if(result != NULL)
2074             break;
2075     }
2076     fail_if(result == NULL);
2077     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "AccessToken"),
2078                       "new-mega-token") != 0);
2079     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "RefreshToken"),
2080                       "new-refresh-token") != 0);
2081     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "TokenType"),
2082                       "Bearer") != 0);
2083     fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
2084     fail_if(expires_in != 1800);
2085     fail_if(g_strcmp0(gsignond_dictionary_get_string(result, "Scope"), "scope1 scope2 scope3") != 0);
2086     
2087     gsignond_dictionary_unref(result);
2088     result = NULL;
2089     fail_if(ui_action != NULL);
2090     fail_if(store == NULL);
2091     GSignondDictionary* client_tokens = gsignond_dictionary_new_from_variant(
2092         gsignond_dictionary_get(store, "megaclient"));
2093     GSignondDictionary* token = gsignond_dictionary_new_from_variant(
2094         gsignond_dictionary_get(client_tokens, "scope1 scope2 scope3"));
2095     fail_if(token == NULL);
2096     
2097     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "AccessToken"),
2098                       "new-mega-token") != 0);
2099     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "RefreshToken"),
2100                       "new-refresh-token") != 0);
2101     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "TokenType"),
2102                       "Bearer") != 0);
2103     fail_if(gsignond_dictionary_get_int64(token, "Duration", &expires_in) != TRUE);
2104     fail_if(expires_in != 1800);
2105     fail_if(g_strcmp0(gsignond_dictionary_get_string(token, "Scope"), "scope1 scope2 scope3") != 0);
2106     
2107     gsignond_dictionary_unref(token);
2108     gsignond_dictionary_unref(client_tokens);
2109
2110     gsignond_dictionary_unref(store);
2111     store = NULL;
2112     fail_if(error != NULL);
2113
2114     gsignond_dictionary_unref(ui_data);
2115     gsignond_dictionary_unref(data);
2116     gsignond_dictionary_unref(tokens);
2117     g_object_unref(plugin);
2118     g_object_unref(server);
2119 }
2120 END_TEST
2121
2122 //printf("%s\n",g_variant_print(gsignond_dictionary_to_variant(store), TRUE));
2123
2124 void add_oauth2_tcase(Suite *s)
2125 {
2126     TCase *tc_oauth2 = tcase_create ("OAuth 2 tests");
2127     tcase_add_test (tc_oauth2, test_oauth2_request);
2128     tcase_add_test (tc_oauth2, test_oauth2_allowed_realms);
2129     tcase_add_test (tc_oauth2, test_oauth2_ui_request);
2130     tcase_add_test (tc_oauth2, test_oauth2_implicit);
2131     tcase_add_test (tc_oauth2, test_oauth2_refresh);
2132     tcase_add_test (tc_oauth2, test_oauth2_client_basic_auth);
2133     tcase_add_test (tc_oauth2, test_oauth2_client_request_body_auth);
2134     tcase_add_test (tc_oauth2, test_oauth2_owner_password);
2135     tcase_add_test (tc_oauth2, test_oauth2_client_credentials);
2136     tcase_add_test (tc_oauth2, test_oauth2_authorization_code);
2137     suite_add_tcase (s, tc_oauth2);
2138 }
2139