1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2012 Intel Corporation.
8 * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
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>
36 static void response_callback(GSignondPlugin* plugin, GSignondSessionData* result,
39 GSignondSessionData** user_data_p = user_data;
40 *user_data_p = result;
41 gsignond_dictionary_ref(result);
44 static void store_callback(GSignondPlugin* plugin, GSignondSessionData* result,
47 response_callback(plugin, result, user_data);
50 static void user_action_required_callback(GSignondPlugin* plugin,
51 GSignondSignonuiData* ui_request,
54 GSignondSignonuiData** user_data_p = user_data;
55 *user_data_p = ui_request;
56 gsignond_dictionary_ref(ui_request);
59 static void error_callback(GSignondPlugin* plugin, GError* error,
62 GError** user_data_p = user_data;
63 *user_data_p = g_error_copy(error);
66 static GVariant* make_normal_token()
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);
82 static GVariant* make_expired_token()
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);
98 static GSignondDictionary* make_tokens(const gchar* client_id, GVariant* token)
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);
108 static GVariant* make_no_refresh_token()
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);
123 static GVariant* make_no_refresh_expired_token()
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);
138 START_TEST (test_oauth2_request)
142 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
143 fail_if(plugin == NULL);
145 GSignondSessionData* result = NULL;
146 GSignondSessionData* store = NULL;
147 GSignondSignonuiData* ui_action = NULL;
148 GError* error = NULL;
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);
156 GSignondSessionData* data = gsignond_dictionary_new();
159 gsignond_plugin_request_initial(plugin, data, NULL, "unknown-mech");
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));
171 gsignond_plugin_request_initial(plugin, data, NULL, "oauth2");
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));
182 gsignond_dictionary_set_string(data, "ClientId", "megaclient");
183 GSignondDictionary* tokens = make_tokens("megaclient", make_normal_token());
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));
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));
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);
221 fail_if(gsignond_dictionary_get_int64(result, "Duration", &expires_in) != TRUE);
222 fail_if(expires_in != 3600);
223 gsignond_dictionary_unref(result);
225 fail_if(ui_action != NULL);
226 fail_if(store != NULL);
227 fail_if(error != NULL);
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);
240 fail_if(ui_action != NULL);
241 fail_if(store != NULL);
242 fail_if(error != NULL);
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);
257 gsignond_dictionary_unref(data);
258 gsignond_dictionary_unref(tokens);
259 g_object_unref(plugin);
263 START_TEST (test_oauth2_allowed_realms)
267 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
268 fail_if(plugin == NULL);
270 GSignondSessionData* result = NULL;
271 GSignondSessionData* store = NULL;
272 GSignondSignonuiData* ui_action = NULL;
273 GError* error = NULL;
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);
281 GSignondSessionData* data = gsignond_dictionary_new();
282 GSignondDictionary* tokens = make_tokens("someclient", make_normal_token());
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");
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);
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);
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);
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);
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);
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);
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);
347 fail_if(store != NULL);
348 fail_if(error != NULL);
350 gsignond_dictionary_unref(data);
351 gsignond_dictionary_unref(tokens);
352 g_object_unref(plugin);
356 START_TEST (test_oauth2_ui_request)
360 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
361 fail_if(plugin == NULL);
363 GSignondSessionData* result = NULL;
364 GSignondSessionData* store = NULL;
365 GSignondSignonuiData* ui_action = NULL;
366 GError* error = NULL;
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);
374 GSignondSessionData* data = gsignond_dictionary_new();
375 GSignondDictionary* tokens = make_tokens("someclient", make_normal_token());
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);
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);
408 gsignond_dictionary_unref(ui_action);
410 fail_if(store != NULL);
411 fail_if(error != NULL);
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");
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);
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);
458 gsignond_dictionary_unref(ui_action);
460 fail_if(store != NULL);
461 fail_if(error != NULL);
463 gsignond_dictionary_unref(data);
464 gsignond_dictionary_unref(tokens);
465 g_object_unref(plugin);
469 START_TEST (test_oauth2_implicit)
473 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
474 fail_if(plugin == NULL);
476 GSignondSessionData* result = NULL;
477 GSignondSessionData* store = NULL;
478 GSignondSignonuiData* ui_action = NULL;
479 GError* error = NULL;
485 //GSignondDictionary* store_tokens;
486 GSignondDictionary* token;
487 GSignondDictionary* client_tokens;
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);
495 GSignondSessionData* data = gsignond_dictionary_new();
496 GSignondDictionary* tokens = make_tokens("someotherclient",
497 make_no_refresh_expired_token());
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);
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);
516 fail_if(store != NULL);
517 fail_if(error != NULL);
519 GSignondSignonuiData* ui_data = gsignond_dictionary_new();
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));
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);
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));
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);
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));
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);
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));
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);
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));
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);
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",
622 url = g_strdup_printf("http://somehost/login.html#%s", params);
623 gsignond_signonui_data_set_url_response(ui_data, url);
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));
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);
642 fail_if(store != NULL);
643 fail_if(error != NULL);
644 params = soup_form_encode("state",
645 gsignond_dictionary_get_string(data, "_Oauth2State"),
647 url = g_strdup_printf("http://somehost/login.html#%s", params);
648 gsignond_signonui_data_set_url_response(ui_data, url);
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));
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);
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",
673 url = g_strdup_printf("http://somehost/login.html#%s", params);
674 gsignond_signonui_data_set_url_response(ui_data, url);
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));
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);
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",
700 url = g_strdup_printf("http://somehost/login.html#%s", params);
701 gsignond_signonui_data_set_url_response(ui_data, url);
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));
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);
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",
727 url = g_strdup_printf("http://somehost/login.html#%s", params);
728 gsignond_signonui_data_set_url_response(ui_data, url);
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"),
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);
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"),
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);
762 gsignond_dictionary_unref(token);
763 gsignond_dictionary_unref(client_tokens);
765 gsignond_dictionary_unref(store);
767 fail_if(error != NULL);
769 //return token and token type but no other parameters, with
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);
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",
786 url = g_strdup_printf("http://somehost/login.html#%s", params);
787 gsignond_signonui_data_set_url_response(ui_data, url);
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"),
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);
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"),
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);
823 gsignond_dictionary_unref(token);
824 gsignond_dictionary_unref(client_tokens);
826 gsignond_dictionary_unref(store);
828 fail_if(error != NULL);
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");
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);
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",
850 url = g_strdup_printf("http://somehost/login.html#%s", params);
851 gsignond_signonui_data_set_url_response(ui_data, url);
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"),
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);
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"),
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);
885 gsignond_dictionary_unref(token);
886 gsignond_dictionary_unref(client_tokens);
888 gsignond_dictionary_unref(store);
890 fail_if(error != NULL);
892 //return token and token type and all other parameters, with
894 gsignond_dictionary_remove(tokens, "megaclient");
895 gsignond_dictionary_remove(data, "Scope");
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);
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",
911 url = g_strdup_printf("http://somehost/login.html#%s", params);
912 gsignond_signonui_data_set_url_response(ui_data, url);
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"),
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);
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"),
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);
946 gsignond_dictionary_unref(token);
947 gsignond_dictionary_unref(client_tokens);
949 gsignond_dictionary_unref(store);
951 fail_if(error != NULL);
953 gsignond_dictionary_unref(ui_data);
954 gsignond_dictionary_unref(data);
955 gsignond_dictionary_unref(tokens);
956 g_object_unref(plugin);
961 refresh_token_server_callback (SoupServer *server,
965 SoupClientContext *client,
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\
975 const gchar* invalid_grant_error = "{\n\
976 \"error\":\"invalid_grant\",\n\
977 \"error_description\":\"some description\",\n\
978 \"error_uri\":\"some uri\"\n\
980 const gchar* generic_error = "{\n\
981 \"error\":\"invalid_request\",\n\
982 \"error_description\":\"some description\",\n\
983 \"error_uri\":\"some uri\"\n\
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);
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);
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",
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",
1008 generic_error, strlen(generic_error));
1010 soup_message_set_status (msg, SOUP_STATUS_OK);
1011 soup_message_set_response (msg, "application/json;charset=UTF-8",
1013 normal_token_response, strlen(normal_token_response));
1017 START_TEST (test_oauth2_refresh)
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",
1025 soup_server_add_handler (server, "/tokenpath", refresh_token_server_callback,
1027 soup_server_run_async(server);
1031 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1032 fail_if(plugin == NULL);
1034 GSignondSessionData* result = NULL;
1035 GSignondSessionData* store = NULL;
1036 GSignondSignonuiData* ui_action = NULL;
1037 GError* error = NULL;
1039 GSignondDictionary* token;
1040 GSignondDictionary* client_tokens;
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);
1052 GSignondSessionData* data = gsignond_dictionary_new();
1053 GSignondDictionary* tokens = make_tokens("megaclient",
1054 make_expired_token());
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);
1068 gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
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);
1077 g_main_context_iteration(g_main_context_default(), TRUE);
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"),
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);
1092 gsignond_dictionary_unref(result);
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);
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"),
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);
1113 gsignond_dictionary_unref(token);
1114 gsignond_dictionary_unref(client_tokens);
1116 gsignond_dictionary_unref(store);
1118 fail_if(error != NULL);
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);
1131 g_main_context_iteration(g_main_context_default(), TRUE);
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);
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);
1156 g_main_context_iteration(g_main_context_default(), TRUE);
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);
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");
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);
1184 g_main_context_iteration(g_main_context_default(), TRUE);
1185 if(ui_action != NULL)
1188 fail_if(result != NULL);
1189 fail_if(ui_action == NULL);
1191 gsignond_dictionary_unref(ui_action);
1193 fail_if(store != NULL);
1194 fail_if(error != NULL);
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);
1205 fail_if(ui_action != NULL);
1206 fail_if(store != NULL);
1207 fail_if(error != NULL);
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);
1218 g_main_context_iteration(g_main_context_default(), TRUE);
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"),
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);
1233 gsignond_dictionary_unref(result);
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);
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"),
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);
1255 gsignond_dictionary_unref(store);
1257 fail_if(error != NULL);
1259 gsignond_dictionary_unref(data);
1260 gsignond_dictionary_unref(tokens);
1261 g_object_unref(plugin);
1262 g_object_unref(server);
1267 client_auth_callback (SoupAuthDomain *domain, SoupMessage *msg,
1268 const char *username, const char *password,
1271 return (g_strcmp0 (password, "megapassword") == 0 &&
1272 g_strcmp0 (username, "megaclient") == 0);
1275 START_TEST (test_oauth2_client_basic_auth)
1277 SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1278 SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
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",
1285 soup_server_add_auth_domain (server, domain);
1286 g_object_unref (domain);
1287 soup_server_add_handler (server, "/tokenpath", refresh_token_server_callback,
1289 soup_server_run_async(server);
1293 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1294 fail_if(plugin == NULL);
1296 GSignondSessionData* result = NULL;
1297 GSignondSessionData* store = NULL;
1298 GSignondSignonuiData* ui_action = NULL;
1299 GError* error = NULL;
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);
1307 GSignondSessionData* data = gsignond_dictionary_new();
1308 GSignondDictionary* tokens = make_tokens("megaclient",
1309 make_expired_token());
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");
1319 gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
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);
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);
1333 g_main_context_iteration(g_main_context_default(), TRUE);
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);
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);
1357 g_main_context_iteration(g_main_context_default(), TRUE);
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);
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);
1382 g_main_context_iteration(g_main_context_default(), TRUE);
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);
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);
1407 g_main_context_iteration(g_main_context_default(), TRUE);
1411 fail_if(result == NULL);
1412 gsignond_dictionary_unref(result);
1414 fail_if(ui_action != NULL);
1415 fail_if(store == NULL);
1416 gsignond_dictionary_unref(store);
1418 fail_if(error != NULL);
1420 gsignond_dictionary_unref(data);
1421 gsignond_dictionary_unref(tokens);
1422 g_object_unref(plugin);
1423 g_object_unref(server);
1429 request_body_auth_server_callback (SoupServer *server,
1433 SoupClientContext *client,
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\
1443 const gchar* invalid_grant_error = "{\n\
1444 \"error\":\"invalid_grant\",\n\
1445 \"error_description\":\"some description\",\n\
1446 \"error_uri\":\"some uri\"\n\
1448 const gchar* generic_error = "{\n\
1449 \"error\":\"invalid_request\",\n\
1450 \"error_description\":\"some description\",\n\
1451 \"error_uri\":\"some uri\"\n\
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);
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);
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) {
1471 g_hash_table_unref(params);
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",
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",
1482 generic_error, strlen(generic_error));
1484 soup_message_set_status (msg, SOUP_STATUS_OK);
1485 soup_message_set_response (msg, "application/json;charset=UTF-8",
1487 normal_token_response, strlen(normal_token_response));
1492 START_TEST (test_oauth2_client_request_body_auth)
1494 SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1495 SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1497 soup_server_add_handler (server, "/tokenpath", request_body_auth_server_callback,
1499 soup_server_run_async(server);
1503 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1504 fail_if(plugin == NULL);
1506 GSignondSessionData* result = NULL;
1507 GSignondSessionData* store = NULL;
1508 GSignondSignonuiData* ui_action = NULL;
1509 GError* error = NULL;
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);
1517 GSignondSessionData* data = gsignond_dictionary_new();
1518 GSignondDictionary* tokens = make_tokens("megaclient",
1519 make_expired_token());
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");
1530 gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
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);
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);
1544 g_main_context_iteration(g_main_context_default(), TRUE);
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);
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);
1568 g_main_context_iteration(g_main_context_default(), TRUE);
1572 fail_if(result == NULL);
1573 gsignond_dictionary_unref(result);
1575 fail_if(ui_action != NULL);
1576 fail_if(store == NULL);
1577 gsignond_dictionary_unref(store);
1579 fail_if(error != NULL);
1581 gsignond_dictionary_unref(data);
1582 gsignond_dictionary_unref(tokens);
1583 g_object_unref(plugin);
1584 g_object_unref(server);
1590 password_token_server_callback (SoupServer *server,
1594 SoupClientContext *client,
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\
1604 const gchar* invalid_grant_error = "{\n\
1605 \"error\":\"invalid_grant\",\n\
1606 \"error_description\":\"some description\",\n\
1607 \"error_uri\":\"some uri\"\n\
1609 const gchar* generic_error = "{\n\
1610 \"error\":\"invalid_request\",\n\
1611 \"error_description\":\"some description\",\n\
1612 \"error_uri\":\"some uri\"\n\
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);
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);
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",
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",
1638 generic_error, strlen(generic_error));
1640 soup_message_set_status (msg, SOUP_STATUS_OK);
1641 soup_message_set_response (msg, "application/json;charset=UTF-8",
1643 normal_token_response, strlen(normal_token_response));
1647 START_TEST (test_oauth2_owner_password)
1649 SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1650 SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1652 soup_server_add_handler (server, "/tokenpath", password_token_server_callback,
1654 soup_server_run_async(server);
1658 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1659 fail_if(plugin == NULL);
1661 GSignondSessionData* result = NULL;
1662 GSignondSessionData* store = NULL;
1663 GSignondSignonuiData* ui_action = NULL;
1664 GError* error = NULL;
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);
1675 GSignondSessionData* data = gsignond_dictionary_new();
1676 GSignondDictionary* tokens = make_tokens("someclient",
1677 make_expired_token());
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");
1687 gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
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);
1694 gsignond_dictionary_set_string(data, "GrantType", "password");
1695 gsignond_session_data_set_username(data, "megauser");
1696 gsignond_session_data_set_secret(data, "megapassword");
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);
1705 g_main_context_iteration(g_main_context_default(), TRUE);
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"),
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);
1720 gsignond_dictionary_unref(result);
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);
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"),
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);
1740 gsignond_dictionary_unref(token);
1741 gsignond_dictionary_unref(client_tokens);
1743 gsignond_dictionary_unref(store);
1745 fail_if(error != NULL);
1747 gsignond_dictionary_unref(data);
1748 gsignond_dictionary_unref(tokens);
1749 g_object_unref(plugin);
1750 g_object_unref(server);
1755 client_credentials_token_server_callback (SoupServer *server,
1759 SoupClientContext *client,
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\
1769 const gchar* invalid_grant_error = "{\n\
1770 \"error\":\"invalid_grant\",\n\
1771 \"error_description\":\"some description\",\n\
1772 \"error_uri\":\"some uri\"\n\
1774 const gchar* generic_error = "{\n\
1775 \"error\":\"invalid_request\",\n\
1776 \"error_description\":\"some description\",\n\
1777 \"error_uri\":\"some uri\"\n\
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);
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);
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",
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",
1801 generic_error, strlen(generic_error));
1803 soup_message_set_status (msg, SOUP_STATUS_OK);
1804 soup_message_set_response (msg, "application/json;charset=UTF-8",
1806 normal_token_response, strlen(normal_token_response));
1810 START_TEST (test_oauth2_client_credentials)
1812 SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1813 SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1815 soup_server_add_handler (server, "/tokenpath", client_credentials_token_server_callback,
1817 soup_server_run_async(server);
1821 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1822 fail_if(plugin == NULL);
1824 GSignondSessionData* result = NULL;
1825 GSignondSessionData* store = NULL;
1826 GSignondSignonuiData* ui_action = NULL;
1827 GError* error = NULL;
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);
1838 GSignondSessionData* data = gsignond_dictionary_new();
1839 GSignondDictionary* tokens = make_tokens("someclient",
1840 make_expired_token());
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);
1854 gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
1856 gsignond_dictionary_set_string(data, "GrantType", "client_credentials");
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);
1865 g_main_context_iteration(g_main_context_default(), TRUE);
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"),
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);
1880 gsignond_dictionary_unref(result);
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);
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"),
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);
1899 gsignond_dictionary_unref(token);
1900 gsignond_dictionary_unref(client_tokens);
1902 gsignond_dictionary_unref(store);
1904 fail_if(error != NULL);
1906 gsignond_dictionary_unref(data);
1907 gsignond_dictionary_unref(tokens);
1908 g_object_unref(plugin);
1909 g_object_unref(server);
1914 authorization_code_token_server_callback (SoupServer *server,
1918 SoupClientContext *client,
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\
1928 const gchar* invalid_grant_error = "{\n\
1929 \"error\":\"invalid_grant\",\n\
1930 \"error_description\":\"some description\",\n\
1931 \"error_uri\":\"some uri\"\n\
1933 const gchar* generic_error = "{\n\
1934 \"error\":\"invalid_request\",\n\
1935 \"error_description\":\"some description\",\n\
1936 \"error_uri\":\"some uri\"\n\
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);
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);
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",
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",
1962 generic_error, strlen(generic_error));
1964 soup_message_set_status (msg, SOUP_STATUS_OK);
1965 soup_message_set_response (msg, "application/json;charset=UTF-8",
1967 normal_token_response, strlen(normal_token_response));
1971 START_TEST (test_oauth2_authorization_code)
1973 SoupServer* server = soup_server_new(SOUP_SERVER_SSL_CERT_FILE, "cacert.pem",
1974 SOUP_SERVER_SSL_KEY_FILE, "privkey.pem",
1976 soup_server_add_handler (server, "/tokenpath", authorization_code_token_server_callback,
1978 soup_server_run_async(server);
1982 plugin = g_object_new(GSIGNOND_TYPE_OAUTH_PLUGIN, NULL);
1983 fail_if(plugin == NULL);
1985 GSignondSessionData* result = NULL;
1986 GSignondSessionData* store = NULL;
1987 GSignondSignonuiData* ui_action = NULL;
1988 GError* error = NULL;
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);
2001 GSignondSessionData* data = gsignond_dictionary_new();
2002 GSignondDictionary* tokens = make_tokens("someclient", make_expired_token());
2003 GSignondSignonuiData* ui_data = gsignond_dictionary_new();
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");
2012 gsignond_dictionary_set_boolean(data, "SslStrict", FALSE);
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);
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);
2029 fail_if(store != NULL);
2030 fail_if(error != NULL);
2032 params = soup_form_encode("state",
2033 gsignond_dictionary_get_string(data, "_Oauth2State"),
2035 url = g_strdup_printf("http://somehost/login.html?%s", params);
2036 gsignond_signonui_data_set_url_response(ui_data, url);
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);
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);
2058 fail_if(store != NULL);
2059 fail_if(error != NULL);
2061 params = soup_form_encode("state",
2062 gsignond_dictionary_get_string(data, "_Oauth2State"),
2063 "code", "mega-auth-code",
2065 url = g_strdup_printf("http://somehost/login.html?%s", params);
2066 gsignond_signonui_data_set_url_response(ui_data, url);
2069 gsignond_plugin_user_action_finished(plugin, ui_data);
2072 g_main_context_iteration(g_main_context_default(), TRUE);
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"),
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);
2087 gsignond_dictionary_unref(result);
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);
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"),
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);
2107 gsignond_dictionary_unref(token);
2108 gsignond_dictionary_unref(client_tokens);
2110 gsignond_dictionary_unref(store);
2112 fail_if(error != NULL);
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);
2122 //printf("%s\n",g_variant_print(gsignond_dictionary_to_variant(store), TRUE));
2124 void add_oauth2_tcase(Suite *s)
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);