Remove const from GLib containers, since GLib container APIs only deal
[platform/upstream/libgsignon-glib.git] / examples / gsso-example.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * Copyright (C) 2013 Intel Corporation.
5  *
6  * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
7  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  */
23
24 #include <glib.h>
25 #include <stdlib.h>
26 #include "libgsignon-glib/signon-auth-service.h"
27 #include "libgsignon-glib/signon-identity.h"
28
29 typedef struct {
30     GMainLoop *main_loop;
31     SignonSecurityContext *security_context;
32 } AclModifyUserData;
33
34 static void
35 signon_query_methods_cb (SignonAuthService *auth_service, gchar **methods,
36                          const GError *error, gpointer user_data)
37 {
38     if (error)
39     {
40         g_warning ("%s: %s", G_STRFUNC, error->message);
41         g_main_loop_quit (user_data);
42         return;
43     }
44
45     gchar **pmethods = methods;
46
47     g_print("Available authentication methods:\n");
48     while (*pmethods)
49     {
50         g_print("\t%s\n", *pmethods);
51         pmethods++;
52     }
53     if (methods) g_strfreev (methods);
54     g_main_loop_quit (user_data);
55 }
56
57 static void query_auth_methods(GMainLoop* main_loop)
58 {
59     SignonAuthService* auth_service = signon_auth_service_new();
60     
61     signon_auth_service_query_methods (auth_service, 
62                                        signon_query_methods_cb,
63                                                        main_loop);
64     g_main_loop_run(main_loop);
65     
66     g_object_unref(auth_service);
67 }
68
69 static void
70 signon_query_mechanisms_cb (SignonAuthService *auth_service,
71                             const gchar *method,
72                             gchar **mechanisms,
73                             const GError *error,
74                             gpointer user_data)
75 {
76     if (error)
77     {
78         g_warning ("%s: %s", G_STRFUNC, error->message);
79         g_main_loop_quit (user_data);
80         return;
81     }
82
83     gchar **pmechanisms = mechanisms;
84
85     g_print("Available authentication mechanisms for method %s:\n", method);
86     while (*pmechanisms)
87     {
88         g_print("\t%s\n", *pmechanisms);
89         pmechanisms++;
90     }
91     if (mechanisms) g_strfreev (mechanisms);
92     g_main_loop_quit (user_data);
93 }
94
95 static void query_auth_mechanisms(GMainLoop* main_loop, const gchar* method)
96 {
97     SignonAuthService* auth_service = signon_auth_service_new();
98     
99     signon_auth_service_query_mechanisms (auth_service,
100                                           method,
101                                           signon_query_mechanisms_cb, 
102                                           main_loop);
103     g_main_loop_run(main_loop);
104     
105     g_object_unref(auth_service);
106 }
107
108 static void signon_query_identities_cb (SignonAuthService *auth_service,
109     SignonIdentityList *identity_list, const GError *error, gpointer user_data)
110 {
111     GList *iter = identity_list;
112     
113     if (error)
114     {
115         g_warning ("%s: %s", G_STRFUNC, error->message);
116         g_main_loop_quit (user_data);
117         return;
118     }
119     
120     g_print("Available identities:\n");
121     while (iter)
122     {
123         SignonIdentityInfo *info = (SignonIdentityInfo *) iter->data;
124         const gchar *caption = signon_identity_info_get_caption (info);
125
126         g_print ("\tid=%d caption='%s' ACL:",
127                  signon_identity_info_get_id (info),
128                  signon_identity_info_get_caption (info));
129
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));
135         }
136         g_print("\n");
137
138         iter = g_list_next (iter);
139     }
140     g_list_free_full (identity_list, (GDestroyNotify)signon_identity_info_free);
141
142     g_main_loop_quit (user_data);
143 }
144
145 static void query_auth_identities(GMainLoop* main_loop)
146 {
147     SignonAuthService* auth_service = signon_auth_service_new();
148     
149     signon_auth_service_query_identities (auth_service,
150                                           NULL, NULL,
151                                           signon_query_identities_cb,
152                                           main_loop);
153     g_main_loop_run(main_loop);
154     
155     g_object_unref(auth_service);
156 }
157
158 static void signon_store_identity_cb(SignonIdentity *self,
159                                                     guint32 id,
160                                                     const GError *error,
161                                                     gpointer user_data)
162 {
163     if (error)
164     {
165         g_warning ("%s: %s", G_STRFUNC, error->message);
166         g_main_loop_quit (user_data);
167         return;
168     }
169
170     g_print("Identity stored with id %d\n", id);
171     g_main_loop_quit (user_data);
172 }
173
174 static void create_auth_identity(GMainLoop* main_loop, const gchar* identity_caption,
175     const gchar* identity_method, const gchar* allowed_realms)
176 {
177     const gchar* all_mechanisms[] = { "*", NULL };
178
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);
185     
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);
190     }
191     
192     signon_identity_store_credentials_with_info (identity,
193                                                  identity_info,
194                                                  signon_store_identity_cb, 
195                                                  main_loop);
196     g_main_loop_run(main_loop);
197     
198     g_object_unref(identity);
199     signon_identity_info_free(identity_info);
200 }
201
202 static void signon_remove_identity_cb(SignonIdentity *self,
203                                                     const GError *error,
204                                                     gpointer user_data)
205 {
206     if (error)
207     {
208         g_warning ("%s: %s", G_STRFUNC, error->message);
209         g_main_loop_quit (user_data);
210         return;
211     }
212
213     g_print("Identity removed\n");
214     g_main_loop_quit (user_data);
215 }
216
217
218 static void remove_auth_identity(GMainLoop* main_loop, gint identity_id)
219 {
220     SignonIdentity* identity = signon_identity_new_from_db(identity_id);
221     signon_identity_remove (identity, 
222                             signon_remove_identity_cb, 
223                             main_loop);
224     g_main_loop_run(main_loop);
225     
226     g_object_unref(identity);
227 }
228
229 static void auth_session_process_cb (GObject *source_object,
230                                       GAsyncResult *res,
231                                       gpointer user_data)
232 {
233     g_debug("%s", G_STRFUNC);
234     SignonAuthSession *auth_session = SIGNON_AUTH_SESSION (source_object);
235     GVariant *v_reply;
236     char *str_reply = NULL;
237     GError *error = NULL;
238
239     v_reply = signon_auth_session_process_finish (auth_session, res, &error);
240     if (error)
241     {
242         g_warning ("%s: %s", G_STRFUNC, error->message);
243         g_error_free(error);
244         g_main_loop_quit (user_data);
245         return;
246     }
247
248     str_reply = g_variant_print (v_reply, TRUE);
249     g_print("Got response: %s\n", str_reply);
250     g_free (str_reply);
251     g_variant_unref(v_reply);
252
253     g_main_loop_quit (user_data);
254 }
255
256
257 static void get_google_token(GMainLoop* main_loop, gint identity_id,
258                              const gchar* client_id, 
259                              const gchar* client_secret)
260 {
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");
263         exit(1);
264     }
265     
266     SignonIdentity* identity = signon_identity_new_from_db(identity_id);
267     SignonAuthSession* session = signon_identity_create_session(identity, "oauth", NULL);
268     
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);
295
296     signon_auth_session_process_async (session,
297                                        session_data,
298                                        "oauth2",
299                                        NULL,
300                                        auth_session_process_cb,
301                                        main_loop);
302     
303     g_print("Geting token\n");
304     g_main_loop_run (main_loop);
305
306     g_object_unref(session);
307     g_object_unref(identity);
308
309
310 static void get_password(GMainLoop* main_loop, gint identity_id)
311 {
312     SignonIdentity* identity = signon_identity_new_from_db(identity_id);
313     SignonAuthSession* session = signon_identity_create_session(identity, "password", NULL);
314     
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);
319
320     signon_auth_session_process_async (session,
321                                        session_data,
322                                        "password",
323                                        NULL,
324                                        auth_session_process_cb,
325                                        main_loop);
326     
327     g_print("Geting password\n");
328     g_main_loop_run (main_loop);
329
330     g_object_unref(session);
331     g_object_unref(identity);
332 }
333
334 static void append_acl_cb(SignonIdentity *self, SignonIdentityInfo *info, const GError *error, gpointer user_data)
335 {
336     AclModifyUserData *am_user_data = (AclModifyUserData *)user_data;
337     SignonIdentityInfo *new_info;
338
339     if (error) {
340         g_warning("%s: %s", G_STRFUNC, error->message);
341         goto clean_user_data;
342     }
343
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);
348
349 clean_user_data:
350     g_free(am_user_data);
351 }
352
353 static void append_acl(GMainLoop* main_loop, gint identity_id, SignonSecurityContext* security_context)
354 {
355     AclModifyUserData *user_data = g_new0(AclModifyUserData, 1);
356     user_data->main_loop = main_loop;
357     user_data->security_context = security_context;
358
359     SignonIdentity* identity = signon_identity_new_from_db(identity_id);
360     signon_identity_query_info(identity, append_acl_cb, user_data);
361
362     g_main_loop_run (main_loop);
363     g_object_unref(identity);
364 }
365
366 static void remove_acl_cb(SignonIdentity *self, SignonIdentityInfo *info, const GError *error, gpointer user_data)
367 {
368     AclModifyUserData *am_user_data = (AclModifyUserData *)user_data;
369
370     if (error) {
371         g_warning("%s: %s", G_STRFUNC, error->message);
372         goto clean_user_data;
373     }
374
375     SignonSecurityContextList *new_list = signon_security_context_list_copy(signon_identity_info_get_access_control_list(info));
376     SignonSecurityContextList *list_iter = new_list;
377
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);
385             list_changed = TRUE;
386             break;
387         }
388         list_iter = g_list_next(list_iter);
389     }
390
391     if (list_changed) {
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);
394     } else {
395         signon_security_context_list_free(new_list);
396         g_main_loop_quit (am_user_data->main_loop);
397     }
398
399 clean_user_data:
400     signon_security_context_free(am_user_data->security_context);
401     g_free(am_user_data);
402 }
403
404 static void remove_acl(GMainLoop* main_loop, gint identity_id, SignonSecurityContext* security_context)
405 {
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;
409
410     SignonIdentity* identity = signon_identity_new_from_db(identity_id);
411     signon_identity_query_info(identity, remove_acl_cb, am_user_data);
412
413     g_main_loop_run (main_loop);
414     g_object_unref(identity);
415 }
416
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);
420     }
421     return NULL;
422 }
423
424 int
425 main (int argc, char *argv[])
426 {
427    
428     GError *error = NULL;
429     GOptionContext *context;
430     GMainLoop* main_loop = NULL;
431     
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;
439     
440     GOptionEntry main_entries[] =
441     {
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"},
449         { NULL }
450     };
451
452     gchar* client_id = NULL;
453     gchar* client_secret = NULL;
454     gint google_identity_id = 0;
455
456     GOptionEntry oauth_entries[] =
457     {
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" },
461         { NULL }
462     };
463
464     gint password_identity_id = 0;
465
466     GOptionEntry password_entries[] =
467     {
468         { "get-password", 0, 0, G_OPTION_ARG_INT, &password_identity_id, "Get an identity's username and password using 'password' plugin", "identity-id"},
469         { NULL }
470     };
471
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;
476
477     GOptionEntry acl_entries[] =
478     {
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"},
483         { NULL }
484     };
485     
486     
487 #if !GLIB_CHECK_VERSION (2, 36, 0)
488     g_type_init ();
489 #endif   
490     
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);
496
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);
500
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);
504     
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);
508         exit (1);
509     }
510     g_option_context_free(context);
511     
512     main_loop = g_main_loop_new(NULL, FALSE);
513     
514     if (query_methods) {
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);
530         if (sec_ctx) {
531             if (add_acl_ctx_id > 0) {
532                 append_acl(main_loop, add_acl_ctx_id, sec_ctx);
533             } else {
534                 remove_acl(main_loop, remove_acl_ctx_id, sec_ctx);
535             }
536         } else {
537             g_print("Must provide security context with --system-context and --application-context options\n");
538         }
539     }
540         
541     g_main_loop_unref(main_loop);
542     if (client_id)
543         g_free (client_id);
544     if (client_secret)
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);
554     if (acl_sys_ctx)
555         g_free(acl_sys_ctx);
556     if (acl_app_ctx)
557         g_free(acl_app_ctx);
558 }