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