soup-auth-manager: add soup_auth_manager_use_auth()
[platform/upstream/libsoup.git] / libsoup / soup-auth.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-auth.c: HTTP Authentication framework
4  *
5  * Copyright (C) 2001-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <string.h>
13
14 #include "soup-auth.h"
15 #include "soup.h"
16 #include "soup-connection-auth.h"
17 #include "soup-marshal.h"
18
19 /**
20  * SECTION:soup-auth
21  * @short_description: HTTP client-side authentication support
22  * @see_also: #SoupSession
23  *
24  * #SoupAuth objects store the authentication data associated with a
25  * given bit of web space. They are created automatically by
26  * #SoupSession.
27  **/
28
29 /**
30  * SoupAuth:
31  *
32  * The abstract base class for handling authentication. Specific HTTP
33  * Authentication mechanisms are implemented by its subclasses, but
34  * applications never need to be aware of the specific subclasses
35  * being used.
36  **/
37
38 typedef struct {
39         gboolean proxy;
40         char *host;
41 } SoupAuthPrivate;
42 #define SOUP_AUTH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH, SoupAuthPrivate))
43
44 G_DEFINE_ABSTRACT_TYPE (SoupAuth, soup_auth, G_TYPE_OBJECT)
45
46 enum {
47         PROP_0,
48
49         PROP_SCHEME_NAME,
50         PROP_REALM,
51         PROP_HOST,
52         PROP_IS_FOR_PROXY,
53         PROP_IS_AUTHENTICATED,
54
55         LAST_PROP
56 };
57
58 static void
59 soup_auth_init (SoupAuth *auth)
60 {
61 }
62
63 static void
64 soup_auth_finalize (GObject *object)
65 {
66         SoupAuth *auth = SOUP_AUTH (object);
67         SoupAuthPrivate *priv = SOUP_AUTH_GET_PRIVATE (auth);
68
69         g_free (auth->realm);
70         g_free (priv->host);
71
72         G_OBJECT_CLASS (soup_auth_parent_class)->finalize (object);
73 }
74
75 static void
76 soup_auth_set_property (GObject *object, guint prop_id,
77                         const GValue *value, GParamSpec *pspec)
78 {
79         SoupAuth *auth = SOUP_AUTH (object);
80         SoupAuthPrivate *priv = SOUP_AUTH_GET_PRIVATE (object);
81
82         switch (prop_id) {
83         case PROP_REALM:
84                 auth->realm = g_value_dup_string (value);
85                 break;
86         case PROP_HOST:
87                 priv->host = g_value_dup_string (value);
88                 break;
89         case PROP_IS_FOR_PROXY:
90                 priv->proxy = g_value_get_boolean (value);
91                 break;
92         default:
93                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
94                 break;
95         }
96 }
97
98 static void
99 soup_auth_get_property (GObject *object, guint prop_id,
100                         GValue *value, GParamSpec *pspec)
101 {
102         SoupAuth *auth = SOUP_AUTH (object);
103         SoupAuthPrivate *priv = SOUP_AUTH_GET_PRIVATE (object);
104
105         switch (prop_id) {
106         case PROP_SCHEME_NAME:
107                 g_value_set_string (value, soup_auth_get_scheme_name (auth));
108                 break;
109         case PROP_REALM:
110                 if (auth->realm)
111                         g_free (auth->realm);
112                 g_value_set_string (value, soup_auth_get_realm (auth));
113                 break;
114         case PROP_HOST:
115                 if (priv->host)
116                         g_free (priv->host);
117                 g_value_set_string (value, soup_auth_get_host (auth));
118                 break;
119         case PROP_IS_FOR_PROXY:
120                 g_value_set_boolean (value, priv->proxy);
121                 break;
122         case PROP_IS_AUTHENTICATED:
123                 g_value_set_boolean (value, soup_auth_is_authenticated (auth));
124                 break;
125         default:
126                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
127                 break;
128         }
129 }
130
131
132 static void
133 soup_auth_class_init (SoupAuthClass *auth_class)
134 {
135         GObjectClass *object_class = G_OBJECT_CLASS (auth_class);
136
137         g_type_class_add_private (auth_class, sizeof (SoupAuthPrivate));
138
139         object_class->finalize     = soup_auth_finalize;
140         object_class->set_property = soup_auth_set_property;
141         object_class->get_property = soup_auth_get_property;
142
143         /* properties */
144         /**
145          * SOUP_AUTH_SCHEME_NAME:
146          *
147          * An alias for the #SoupAuth:scheme-name property. (The
148          * authentication scheme name.)
149          **/
150         g_object_class_install_property (
151                 object_class, PROP_SCHEME_NAME,
152                 g_param_spec_string (SOUP_AUTH_SCHEME_NAME,
153                                      "Scheme name",
154                                      "Authentication scheme name",
155                                      NULL,
156                                      G_PARAM_READABLE));
157         /**
158          * SOUP_AUTH_REALM:
159          *
160          * An alias for the #SoupAuth:realm property. (The
161          * authentication realm.)
162          **/
163         g_object_class_install_property (
164                 object_class, PROP_REALM,
165                 g_param_spec_string (SOUP_AUTH_REALM,
166                                      "Realm",
167                                      "Authentication realm",
168                                      NULL,
169                                      G_PARAM_READWRITE));
170         /**
171          * SOUP_AUTH_HOST:
172          *
173          * An alias for the #SoupAuth:host property. (The
174          * host being authenticated to.)
175          **/
176         g_object_class_install_property (
177                 object_class, PROP_HOST,
178                 g_param_spec_string (SOUP_AUTH_HOST,
179                                      "Host",
180                                      "Authentication host",
181                                      NULL,
182                                      G_PARAM_READWRITE));
183         /**
184          * SOUP_AUTH_IS_FOR_PROXY:
185          *
186          * An alias for the #SoupAuth:is-for-proxy property. (Whether
187          * or not the auth is for a proxy server.)
188          **/
189         g_object_class_install_property (
190                 object_class, PROP_IS_FOR_PROXY,
191                 g_param_spec_boolean (SOUP_AUTH_IS_FOR_PROXY,
192                                       "For Proxy",
193                                       "Whether or not the auth is for a proxy server",
194                                       FALSE,
195                                       G_PARAM_READWRITE));
196         /**
197          * SOUP_AUTH_IS_AUTHENTICATED:
198          *
199          * An alias for the #SoupAuth:is-authenticated property.
200          * (Whether or not the auth has been authenticated.)
201          **/
202         g_object_class_install_property (
203                 object_class, PROP_IS_AUTHENTICATED,
204                 g_param_spec_boolean (SOUP_AUTH_IS_AUTHENTICATED,
205                                       "Authenticated",
206                                       "Whether or not the auth is authenticated",
207                                       FALSE,
208                                       G_PARAM_READABLE));
209 }
210
211 /**
212  * soup_auth_new:
213  * @type: the type of auth to create (a subtype of #SoupAuth)
214  * @msg: the #SoupMessage the auth is being created for
215  * @auth_header: the WWW-Authenticate/Proxy-Authenticate header
216  *
217  * Creates a new #SoupAuth of type @type with the information from
218  * @msg and @auth_header.
219  *
220  * This is called by #SoupSession; you will normally not create auths
221  * yourself.
222  *
223  * Return value: the new #SoupAuth, or %NULL if it could not be
224  * created
225  **/
226 SoupAuth *
227 soup_auth_new (GType type, SoupMessage *msg, const char *auth_header)
228 {
229         SoupAuth *auth;
230         GHashTable *params;
231         const char *scheme, *realm;
232
233         g_return_val_if_fail (g_type_is_a (type, SOUP_TYPE_AUTH), NULL);
234         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
235         g_return_val_if_fail (auth_header != NULL, NULL);
236
237         auth = g_object_new (type,
238                              SOUP_AUTH_IS_FOR_PROXY, (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED),
239                              SOUP_AUTH_HOST, soup_message_get_uri (msg)->host,
240                              NULL);
241
242         scheme = soup_auth_get_scheme_name (auth);
243         if (g_ascii_strncasecmp (auth_header, scheme, strlen (scheme)) != 0) {
244                 g_object_unref (auth);
245                 return NULL;
246         }
247
248         params = soup_header_parse_param_list (auth_header + strlen (scheme));
249         if (!params)
250                 params = g_hash_table_new (NULL, NULL);
251
252         realm = g_hash_table_lookup (params, "realm");
253         if (realm)
254                 auth->realm = g_strdup (realm);
255
256         if (!SOUP_AUTH_GET_CLASS (auth)->update (auth, msg, params)) {
257                 g_object_unref (auth);
258                 auth = NULL;
259         }
260         soup_header_free_param_list (params);
261         return auth;
262 }
263
264 /**
265  * soup_auth_update:
266  * @auth: a #SoupAuth
267  * @msg: the #SoupMessage @auth is being updated for
268  * @auth_header: the WWW-Authenticate/Proxy-Authenticate header
269  *
270  * Updates @auth with the information from @msg and @auth_header,
271  * possibly un-authenticating it. As with soup_auth_new(), this is
272  * normally only used by #SoupSession.
273  *
274  * Return value: %TRUE if @auth is still a valid (but potentially
275  * unauthenticated) #SoupAuth. %FALSE if something about @auth_params
276  * could not be parsed or incorporated into @auth at all.
277  **/
278 gboolean
279 soup_auth_update (SoupAuth *auth, SoupMessage *msg, const char *auth_header)
280 {
281         GHashTable *params;
282         const char *scheme, *realm;
283         gboolean was_authenticated, success;
284
285         g_return_val_if_fail (SOUP_IS_AUTH (auth), FALSE);
286         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
287         g_return_val_if_fail (auth_header != NULL, FALSE);
288
289         scheme = soup_auth_get_scheme_name (auth);
290         if (g_ascii_strncasecmp (auth_header, scheme, strlen (scheme)) != 0)
291                 return FALSE;
292
293         params = soup_header_parse_param_list (auth_header + strlen (scheme));
294         if (!params)
295                 params = g_hash_table_new (NULL, NULL);
296
297         realm = g_hash_table_lookup (params, "realm");
298         if (realm && auth->realm && strcmp (realm, auth->realm) != 0) {
299                 soup_header_free_param_list (params);
300                 return FALSE;
301         }
302
303         was_authenticated = soup_auth_is_authenticated (auth);
304         success = SOUP_AUTH_GET_CLASS (auth)->update (auth, msg, params);
305         if (was_authenticated != soup_auth_is_authenticated (auth))
306                 g_object_notify (G_OBJECT (auth), SOUP_AUTH_IS_AUTHENTICATED);
307         soup_header_free_param_list (params);
308         return success;
309 }
310
311 /**
312  * soup_auth_authenticate:
313  * @auth: a #SoupAuth
314  * @username: the username provided by the user or client
315  * @password: the password provided by the user or client
316  *
317  * Call this on an auth to authenticate it; normally this will cause
318  * the auth's message to be requeued with the new authentication info.
319  **/
320 void
321 soup_auth_authenticate (SoupAuth *auth, const char *username, const char *password)
322 {
323         gboolean was_authenticated;
324
325         g_return_if_fail (SOUP_IS_AUTH (auth));
326         g_return_if_fail (username != NULL);
327         g_return_if_fail (password != NULL);
328
329         was_authenticated = soup_auth_is_authenticated (auth);
330         SOUP_AUTH_GET_CLASS (auth)->authenticate (auth, username, password);
331         if (was_authenticated != soup_auth_is_authenticated (auth))
332                 g_object_notify (G_OBJECT (auth), SOUP_AUTH_IS_AUTHENTICATED);
333 }
334
335 /**
336  * soup_auth_is_for_proxy:
337  * @auth: a #SoupAuth
338  *
339  * Tests whether or not @auth is associated with a proxy server rather
340  * than an "origin" server.
341  *
342  * Return value: %TRUE or %FALSE
343  **/
344 gboolean
345 soup_auth_is_for_proxy (SoupAuth *auth)
346 {
347         g_return_val_if_fail (SOUP_IS_AUTH (auth), FALSE);
348
349         return SOUP_AUTH_GET_PRIVATE (auth)->proxy;
350 }
351
352 /**
353  * soup_auth_get_scheme_name:
354  * @auth: a #SoupAuth
355  *
356  * Returns @auth's scheme name. (Eg, "Basic", "Digest", or "NTLM")
357  *
358  * Return value: the scheme name
359  **/
360 const char *
361 soup_auth_get_scheme_name (SoupAuth *auth)
362 {
363         g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
364
365         return SOUP_AUTH_GET_CLASS (auth)->scheme_name;
366 }
367
368 /**
369  * soup_auth_get_host:
370  * @auth: a #SoupAuth
371  *
372  * Returns the host that @auth is associated with.
373  *
374  * Return value: the hostname
375  **/
376 const char *
377 soup_auth_get_host (SoupAuth *auth)
378 {
379         g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
380
381         return SOUP_AUTH_GET_PRIVATE (auth)->host;
382 }
383
384
385 /**
386  * soup_auth_get_realm:
387  * @auth: a #SoupAuth
388  *
389  * Returns @auth's realm. This is an identifier that distinguishes
390  * separate authentication spaces on a given server, and may be some
391  * string that is meaningful to the user. (Although it is probably not
392  * localized.)
393  *
394  * Return value: the realm name
395  **/
396 const char *
397 soup_auth_get_realm (SoupAuth *auth)
398 {
399         g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
400
401         return auth->realm;
402 }
403
404 /**
405  * soup_auth_get_info:
406  * @auth: a #SoupAuth
407  *
408  * Gets an opaque identifier for @auth, for use as a hash key or the
409  * like. #SoupAuth objects from the same server with the same
410  * identifier refer to the same authentication domain (eg, the URLs
411  * associated with them take the same usernames and passwords).
412  *
413  * Return value: the identifier
414  **/
415 char *
416 soup_auth_get_info (SoupAuth *auth)
417 {
418         g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
419
420         if (SOUP_IS_CONNECTION_AUTH (auth))
421                 return g_strdup (SOUP_AUTH_GET_CLASS (auth)->scheme_name);
422         else {
423                 return g_strdup_printf ("%s:%s",
424                                         SOUP_AUTH_GET_CLASS (auth)->scheme_name,
425                                         auth->realm);
426         }
427 }
428
429 /**
430  * soup_auth_is_authenticated:
431  * @auth: a #SoupAuth
432  *
433  * Tests if @auth has been given a username and password
434  *
435  * Return value: %TRUE if @auth has been given a username and password
436  **/
437 gboolean
438 soup_auth_is_authenticated (SoupAuth *auth)
439 {
440         g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
441
442         return SOUP_AUTH_GET_CLASS (auth)->is_authenticated (auth);
443 }
444
445 /**
446  * soup_auth_get_authorization:
447  * @auth: a #SoupAuth
448  * @msg: the #SoupMessage to be authorized
449  *
450  * Generates an appropriate "Authorization" header for @msg. (The
451  * session will only call this if soup_auth_is_authenticated()
452  * returned %TRUE.)
453  *
454  * Return value: the "Authorization" header, which must be freed.
455  **/
456 char *
457 soup_auth_get_authorization (SoupAuth *auth, SoupMessage *msg)
458 {
459         g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
460         g_return_val_if_fail (msg != NULL, NULL);
461
462         return SOUP_AUTH_GET_CLASS (auth)->get_authorization (auth, msg);
463 }
464
465 /**
466  * soup_auth_is_ready:
467  * @auth: a #SoupAuth
468  * @msg: a #SoupMessage
469  *
470  * Tests if @auth is ready to make a request for @msg with. For most
471  * auths, this is equivalent to soup_auth_is_authenticated(), but for
472  * some auth types (eg, NTLM), the auth may be sendable (eg, as an
473  * authentication request) even before it is authenticated.
474  *
475  * Return value: %TRUE if @auth is ready to make a request with.
476  *
477  * Since: 2.42
478  **/
479 gboolean
480 soup_auth_is_ready (SoupAuth    *auth,
481                     SoupMessage *msg)
482 {
483         g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
484         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), TRUE);
485
486         if (SOUP_AUTH_GET_CLASS (auth)->is_ready)
487                 return SOUP_AUTH_GET_CLASS (auth)->is_ready (auth, msg);
488         else
489                 return SOUP_AUTH_GET_CLASS (auth)->is_authenticated (auth);
490 }
491
492 /**
493  * soup_auth_get_protection_space:
494  * @auth: a #SoupAuth
495  * @source_uri: the URI of the request that @auth was generated in
496  * response to.
497  *
498  * Returns a list of paths on the server which @auth extends over.
499  * (All subdirectories of these paths are also assumed to be part
500  * of @auth's protection space, unless otherwise discovered not to
501  * be.)
502  *
503  * Return value: (element-type utf8) (transfer full): the list of
504  * paths, which can be freed with soup_auth_free_protection_space().
505  **/
506 GSList *
507 soup_auth_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
508 {
509         g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
510         g_return_val_if_fail (source_uri != NULL, NULL);
511
512         return SOUP_AUTH_GET_CLASS (auth)->get_protection_space (auth, source_uri);
513 }
514
515 /**
516  * soup_auth_free_protection_space: (skip)
517  * @auth: a #SoupAuth
518  * @space: the return value from soup_auth_get_protection_space()
519  *
520  * Frees @space.
521  **/
522 void
523 soup_auth_free_protection_space (SoupAuth *auth, GSList *space)
524 {
525         g_slist_free_full (space, g_free);
526 }
527
528 GSList *
529 soup_auth_get_saved_users (SoupAuth *auth)
530 {
531         return NULL;
532 }
533
534 const char *
535 soup_auth_get_saved_password (SoupAuth *auth, const char *user)
536 {
537         return NULL;
538 }
539
540 void
541 soup_auth_has_saved_password (SoupAuth *auth, const char *username,
542                               const char *password)
543 {
544 }
545
546 void
547 soup_auth_save_password (SoupAuth *auth, const char *username,
548                          const char *password)
549 {
550 }