1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * Copyright (C) 2013 Intel Corporation.
6 * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 #include "libgsignon-glib/signon-auth-service.h"
27 #include "libgsignon-glib/signon-identity.h"
31 SignonSecurityContext *security_context;
35 signon_query_methods_cb (SignonAuthService *auth_service, gchar **methods,
36 const GError *error, gpointer user_data)
40 g_warning ("%s: %s", G_STRFUNC, error->message);
41 g_main_loop_quit (user_data);
45 gchar **pmethods = methods;
47 g_print("Available authentication methods:\n");
50 g_print("\t%s\n", *pmethods);
53 if (methods) g_strfreev (methods);
54 g_main_loop_quit (user_data);
57 static void query_auth_methods(GMainLoop* main_loop)
59 SignonAuthService* auth_service = signon_auth_service_new();
61 signon_auth_service_query_methods (auth_service,
62 signon_query_methods_cb,
64 g_main_loop_run(main_loop);
66 g_object_unref(auth_service);
70 signon_query_mechanisms_cb (SignonAuthService *auth_service,
78 g_warning ("%s: %s", G_STRFUNC, error->message);
79 g_main_loop_quit (user_data);
83 gchar **pmechanisms = mechanisms;
85 g_print("Available authentication mechanisms for method %s:\n", method);
88 g_print("\t%s\n", *pmechanisms);
91 if (mechanisms) g_strfreev (mechanisms);
92 g_main_loop_quit (user_data);
95 static void query_auth_mechanisms(GMainLoop* main_loop, const gchar* method)
97 SignonAuthService* auth_service = signon_auth_service_new();
99 signon_auth_service_query_mechanisms (auth_service,
101 signon_query_mechanisms_cb,
103 g_main_loop_run(main_loop);
105 g_object_unref(auth_service);
108 static void signon_query_identities_cb (SignonAuthService *auth_service,
109 SignonIdentityList *identity_list, const GError *error, gpointer user_data)
111 GList *iter = identity_list;
115 g_warning ("%s: %s", G_STRFUNC, error->message);
116 g_main_loop_quit (user_data);
120 g_print("Available identities:\n");
123 SignonIdentityInfo *info = (SignonIdentityInfo *) iter->data;
124 const gchar *caption = signon_identity_info_get_caption (info);
126 g_print ("\tid=%d caption='%s' ACL:",
127 signon_identity_info_get_id (info),
128 signon_identity_info_get_caption (info));
130 SignonSecurityContextList *acl = signon_identity_info_get_access_control_list(info);
131 for(acl = g_list_first(acl); acl != NULL; acl = g_list_next(acl)) {
132 const SignonSecurityContext *context = acl->data;
133 g_print(" (%s:%s)", signon_security_context_get_system_context(context),
134 signon_security_context_get_application_context(context));
138 iter = g_list_next (iter);
140 g_list_free_full (identity_list, (GDestroyNotify)signon_identity_info_free);
142 g_main_loop_quit (user_data);
145 static void query_auth_identities(GMainLoop* main_loop)
147 SignonAuthService* auth_service = signon_auth_service_new();
149 signon_auth_service_query_identities (auth_service,
151 signon_query_identities_cb,
153 g_main_loop_run(main_loop);
155 g_object_unref(auth_service);
158 static void signon_store_identity_cb(SignonIdentity *self,
165 g_warning ("%s: %s", G_STRFUNC, error->message);
166 g_main_loop_quit (user_data);
170 g_print("Identity stored with id %d\n", id);
171 g_main_loop_quit (user_data);
174 static void create_auth_identity(GMainLoop* main_loop, const gchar* identity_caption,
175 const gchar* identity_method, const gchar* allowed_realms)
177 const gchar* all_mechanisms[] = { "*", NULL };
179 SignonIdentity* identity = signon_identity_new();
180 SignonIdentityInfo* identity_info = signon_identity_info_new();
181 signon_identity_info_set_caption(identity_info, identity_caption);
182 signon_identity_info_set_method(identity_info, identity_method, all_mechanisms);
183 if (g_strcmp0(identity_method, "password") == 0)
184 signon_identity_info_set_secret(identity_info, NULL, TRUE);
186 if (allowed_realms != NULL) {
187 gchar** realms_array = g_strsplit(allowed_realms, ",", 0);
188 signon_identity_info_set_realms(identity_info, (const gchar* const *) realms_array);
189 g_strfreev(realms_array);
192 signon_identity_store_credentials_with_info (identity,
194 signon_store_identity_cb,
196 g_main_loop_run(main_loop);
198 g_object_unref(identity);
199 signon_identity_info_free(identity_info);
202 static void signon_remove_identity_cb(SignonIdentity *self,
208 g_warning ("%s: %s", G_STRFUNC, error->message);
209 g_main_loop_quit (user_data);
213 g_print("Identity removed\n");
214 g_main_loop_quit (user_data);
218 static void remove_auth_identity(GMainLoop* main_loop, gint identity_id)
220 SignonIdentity* identity = signon_identity_new_from_db(identity_id);
221 signon_identity_remove (identity,
222 signon_remove_identity_cb,
224 g_main_loop_run(main_loop);
226 g_object_unref(identity);
229 static void auth_session_process_cb (GObject *source_object,
233 g_debug("%s", G_STRFUNC);
234 SignonAuthSession *auth_session = SIGNON_AUTH_SESSION (source_object);
236 char *str_reply = NULL;
237 GError *error = NULL;
239 v_reply = signon_auth_session_process_finish (auth_session, res, &error);
242 g_warning ("%s: %s", G_STRFUNC, error->message);
244 g_main_loop_quit (user_data);
248 str_reply = g_variant_print (v_reply, TRUE);
249 g_print("Got response: %s\n", str_reply);
251 g_variant_unref(v_reply);
253 g_main_loop_quit (user_data);
257 static void get_google_token(GMainLoop* main_loop, gint identity_id,
258 const gchar* client_id,
259 const gchar* client_secret)
261 if (!client_id || !client_secret) {
262 g_print("Must provide a client ID and secret (get them at https://code.google.com/apis/console/ )\n");
266 SignonIdentity* identity = signon_identity_new_from_db(identity_id);
267 SignonAuthSession* session = signon_identity_create_session(identity, "oauth", NULL);
269 GVariantBuilder builder;
270 GVariant* session_data;
271 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
272 g_variant_builder_add (&builder, "{sv}",
273 "ClientId", g_variant_new_string (client_id));
274 g_variant_builder_add (&builder, "{sv}",
275 "ClientSecret", g_variant_new_string (client_secret));
276 g_variant_builder_add (&builder, "{sv}",
277 "UiPolicy", g_variant_new_uint32 (SIGNON_POLICY_DEFAULT));
278 g_variant_builder_add (&builder, "{sv}",
279 "ResponseType", g_variant_new_string ("code"));
280 g_variant_builder_add (&builder, "{sv}",
281 "AuthHost", g_variant_new_string ("accounts.google.com"));
282 g_variant_builder_add (&builder, "{sv}",
283 "AuthPath", g_variant_new_string ("/o/oauth2/auth"));
284 g_variant_builder_add (&builder, "{sv}",
285 "RedirectUri", g_variant_new_string("https://localhost"));
286 g_variant_builder_add (&builder, "{sv}",
287 "Scope", g_variant_new_string ("email"));
288 g_variant_builder_add (&builder, "{sv}",
289 "ForceClientAuthViaRequestBody", g_variant_new_boolean(TRUE));
290 g_variant_builder_add (&builder, "{sv}",
291 "TokenHost", g_variant_new_string("accounts.google.com"));
292 g_variant_builder_add (&builder, "{sv}",
293 "TokenPath", g_variant_new_string("/o/oauth2/token"));
294 session_data = g_variant_builder_end (&builder);
296 signon_auth_session_process_async (session,
300 auth_session_process_cb,
303 g_print("Geting token\n");
304 g_main_loop_run (main_loop);
306 g_object_unref(session);
307 g_object_unref(identity);
310 static void get_password(GMainLoop* main_loop, gint identity_id)
312 SignonIdentity* identity = signon_identity_new_from_db(identity_id);
313 SignonAuthSession* session = signon_identity_create_session(identity, "password", NULL);
315 GVariantBuilder builder;
316 GVariant* session_data;
317 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
318 session_data = g_variant_builder_end (&builder);
320 signon_auth_session_process_async (session,
324 auth_session_process_cb,
327 g_print("Geting password\n");
328 g_main_loop_run (main_loop);
330 g_object_unref(session);
331 g_object_unref(identity);
334 static void append_acl_cb(SignonIdentity *self, SignonIdentityInfo *info, const GError *error, gpointer user_data)
336 AclModifyUserData *am_user_data = (AclModifyUserData *)user_data;
337 SignonIdentityInfo *new_info;
340 g_warning("%s: %s", G_STRFUNC, error->message);
341 goto clean_user_data;
344 new_info = signon_identity_info_copy(info);
345 signon_identity_info_access_control_list_append(new_info, am_user_data->security_context);
346 signon_identity_store_credentials_with_info(self, new_info, signon_store_identity_cb, am_user_data->main_loop);
347 signon_identity_info_free(new_info);
350 g_free(am_user_data);
353 static void append_acl(GMainLoop* main_loop, gint identity_id, SignonSecurityContext* security_context)
355 AclModifyUserData *user_data = g_new0(AclModifyUserData, 1);
356 user_data->main_loop = main_loop;
357 user_data->security_context = security_context;
359 SignonIdentity* identity = signon_identity_new_from_db(identity_id);
360 signon_identity_query_info(identity, append_acl_cb, user_data);
362 g_main_loop_run (main_loop);
363 g_object_unref(identity);
366 static void remove_acl_cb(SignonIdentity *self, SignonIdentityInfo *info, const GError *error, gpointer user_data)
368 AclModifyUserData *am_user_data = (AclModifyUserData *)user_data;
371 g_warning("%s: %s", G_STRFUNC, error->message);
372 goto clean_user_data;
375 SignonSecurityContextList *new_list = signon_security_context_list_copy(signon_identity_info_get_access_control_list(info));
376 SignonSecurityContextList *list_iter = new_list;
378 gboolean list_changed = FALSE;
379 while(list_iter != NULL) {
380 SignonSecurityContext *curr_context = list_iter->data;
381 if (g_strcmp0(signon_security_context_get_system_context(curr_context), am_user_data->security_context->sys_ctx) == 0
382 && g_strcmp0(signon_security_context_get_application_context(curr_context), am_user_data->security_context->app_ctx) == 0) {
383 signon_security_context_free(curr_context);
384 new_list = g_list_remove_link(new_list, list_iter);
388 list_iter = g_list_next(list_iter);
392 signon_identity_info_set_access_control_list(info, new_list);
393 signon_identity_store_credentials_with_info(self, info, signon_store_identity_cb, am_user_data->main_loop);
395 signon_security_context_list_free(new_list);
396 g_main_loop_quit (am_user_data->main_loop);
400 signon_security_context_free(am_user_data->security_context);
401 g_free(am_user_data);
404 static void remove_acl(GMainLoop* main_loop, gint identity_id, SignonSecurityContext* security_context)
406 AclModifyUserData *am_user_data = g_new0(AclModifyUserData, 1);
407 am_user_data->main_loop = main_loop;
408 am_user_data->security_context = security_context;
410 SignonIdentity* identity = signon_identity_new_from_db(identity_id);
411 signon_identity_query_info(identity, remove_acl_cb, am_user_data);
413 g_main_loop_run (main_loop);
414 g_object_unref(identity);
417 SignonSecurityContext *create_security_context_from_args(const gchar *sys_ctx, const gchar *app_ctx) {
418 if (sys_ctx && app_ctx) {
419 return signon_security_context_new_from_values(sys_ctx, app_ctx);
425 main (int argc, char *argv[])
428 GError *error = NULL;
429 GOptionContext *context;
430 GMainLoop* main_loop = NULL;
432 gboolean query_methods = FALSE;
433 gchar* query_mechanisms_method = NULL;
434 gboolean query_identities = FALSE;
435 gchar* create_identity_caption = NULL;
436 gchar* create_identity_method = NULL;
437 gchar* create_identity_realms = NULL;
438 gint remove_identity_id = 0;
440 GOptionEntry main_entries[] =
442 { "query-methods", 0, 0, G_OPTION_ARG_NONE, &query_methods, "Query available authentication methods", NULL},
443 { "query-mechanisms", 0, 0, G_OPTION_ARG_STRING, &query_mechanisms_method, "Query available mechanisms for an authentication method", "method"},
444 { "query-identities", 0, 0, G_OPTION_ARG_NONE, &query_identities, "Query available authentication identities", NULL},
445 { "create-identity", 0, 0, G_OPTION_ARG_STRING, &create_identity_caption, "Create a new authentication identity", "caption"},
446 { "identity-method", 0, 0, G_OPTION_ARG_STRING, &create_identity_method, "Method to use when creating identity", "method"},
447 { "identity-realms", 0, 0, G_OPTION_ARG_STRING, &create_identity_realms, "A comma-separated list of allowed realms for the identity", "realms"},
448 { "remove-identity", 0, 0, G_OPTION_ARG_INT, &remove_identity_id, "Remove an authentication identity", "id"},
452 gchar* client_id = NULL;
453 gchar* client_secret = NULL;
454 gint google_identity_id = 0;
456 GOptionEntry oauth_entries[] =
458 { "get-google-token", 0, 0, G_OPTION_ARG_INT, &google_identity_id, "Get an OAuth2 access token from Google", "identity-id"},
459 { "client-id", 0, 0, G_OPTION_ARG_STRING, &client_id, "Client ID", "id" },
460 { "client-secret", 0, 0, G_OPTION_ARG_STRING, &client_secret, "Client secret", "secret" },
464 gint password_identity_id = 0;
466 GOptionEntry password_entries[] =
468 { "get-password", 0, 0, G_OPTION_ARG_INT, &password_identity_id, "Get an identity's username and password using 'password' plugin", "identity-id"},
472 gint add_acl_ctx_id = 0;
473 gint remove_acl_ctx_id = 0;
474 gchar *acl_sys_ctx = NULL;
475 gchar *acl_app_ctx = NULL;
477 GOptionEntry acl_entries[] =
479 { "add-context", 0, 0, G_OPTION_ARG_INT, &add_acl_ctx_id, "Add security context to identity", "identity-id"},
480 { "remove-context", 0, 0, G_OPTION_ARG_INT, &remove_acl_ctx_id, "Remove security context from identity", "identity-id"},
481 { "system-context", 0, 0, G_OPTION_ARG_STRING, &acl_sys_ctx, "System context", "system-context"},
482 { "application-context", 0, 0, G_OPTION_ARG_STRING, &acl_app_ctx, "Application context", "application-context"},
487 #if !GLIB_CHECK_VERSION (2, 36, 0)
491 context = g_option_context_new ("- gSSO application example");
492 g_option_context_add_main_entries (context, main_entries, NULL);
493 GOptionGroup* oauth_group = g_option_group_new("oauth", "OAuth-specific options", "OAuth-specific options", NULL, NULL);
494 g_option_group_add_entries(oauth_group, oauth_entries);
495 g_option_context_add_group (context, oauth_group);
497 GOptionGroup* password_group = g_option_group_new("password", "Password-specific options", "Password-specific options", NULL, NULL);
498 g_option_group_add_entries(password_group, password_entries);
499 g_option_context_add_group (context, password_group);
501 GOptionGroup* acl_group = g_option_group_new("acl", "ACL-specific options", "ACL-specific options", NULL, NULL);
502 g_option_group_add_entries(acl_group, acl_entries);
503 g_option_context_add_group (context, acl_group);
505 if (!g_option_context_parse (context, &argc, &argv, &error)) {
506 g_print ("option parsing failed: %s\n", error->message);
507 g_option_context_free(context);
510 g_option_context_free(context);
512 main_loop = g_main_loop_new(NULL, FALSE);
515 query_auth_methods(main_loop);
516 } else if (query_mechanisms_method) {
517 query_auth_mechanisms(main_loop, query_mechanisms_method);
518 } else if (query_identities) {
519 query_auth_identities(main_loop);
520 } else if (create_identity_caption) {
521 create_auth_identity(main_loop, create_identity_caption, create_identity_method, create_identity_realms);
522 } else if (remove_identity_id > 0) {
523 remove_auth_identity(main_loop, remove_identity_id);
524 } else if (google_identity_id > 0) {
525 get_google_token(main_loop, google_identity_id, client_id, client_secret);
526 } else if (password_identity_id > 0) {
527 get_password(main_loop, password_identity_id);
528 } else if (add_acl_ctx_id > 0 || remove_acl_ctx_id) {
529 SignonSecurityContext *sec_ctx = create_security_context_from_args(acl_sys_ctx, acl_app_ctx);
531 if (add_acl_ctx_id > 0) {
532 append_acl(main_loop, add_acl_ctx_id, sec_ctx);
534 remove_acl(main_loop, remove_acl_ctx_id, sec_ctx);
537 g_print("Must provide security context with --system-context and --application-context options\n");
541 g_main_loop_unref(main_loop);
545 g_free(client_secret);
546 if (query_mechanisms_method)
547 g_free(query_mechanisms_method);
548 if (create_identity_caption)
549 g_free(create_identity_caption);
550 if (create_identity_method)
551 g_free(create_identity_method);
552 if (create_identity_realms)
553 g_free(create_identity_realms);