• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-auth-domain.c: HTTP Authentication Domain (server-side)
4  *
5  * Copyright (C) 2007 Novell, Inc.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <string.h>
13 
14 #include "soup-auth-domain.h"
15 #include "soup.h"
16 #include "soup-path-map.h"
17 
18 /**
19  * SECTION:soup-auth-domain
20  * @short_description: Server-side authentication
21  * @see_also: #SoupServer
22  *
23  * A #SoupAuthDomain manages authentication for all or part of a
24  * #SoupServer. To make a server require authentication, first create
25  * an appropriate subclass of #SoupAuthDomain, and then add it to the
26  * server with soup_server_add_auth_domain().
27  *
28  * In order for an auth domain to have any effect, you must add one or
29  * more paths to it (via soup_auth_domain_add_path() or the
30  * %SOUP_AUTH_DOMAIN_ADD_PATH property). To require authentication for
31  * all ordinary requests, add the path "/". (Note that this does not
32  * include the special "*" URI (eg, "OPTIONS *"), which must be added
33  * as a separate path if you want to cover it.)
34  *
35  * If you need greater control over which requests should and
36  * shouldn't be authenticated, add paths covering everything you
37  * <emphasis>might</emphasis> want authenticated, and then use a
38  * filter (soup_auth_domain_set_filter()) to bypass authentication for
39  * those requests that don't need it.
40  **/
41 
42 enum {
43 	PROP_0,
44 
45 	PROP_REALM,
46 	PROP_PROXY,
47 	PROP_ADD_PATH,
48 	PROP_REMOVE_PATH,
49 	PROP_FILTER,
50 	PROP_FILTER_DATA,
51 	PROP_GENERIC_AUTH_CALLBACK,
52 	PROP_GENERIC_AUTH_DATA,
53 
54 	LAST_PROP
55 };
56 
57 typedef struct {
58 	char *realm;
59 	gboolean proxy;
60 	SoupPathMap *paths;
61 
62 	SoupAuthDomainFilter filter;
63 	gpointer filter_data;
64 	GDestroyNotify filter_dnotify;
65 
66 	SoupAuthDomainGenericAuthCallback auth_callback;
67 	gpointer auth_data;
68 	GDestroyNotify auth_dnotify;
69 
70 } SoupAuthDomainPrivate;
71 
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(SoupAuthDomain,soup_auth_domain,G_TYPE_OBJECT)72 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (SoupAuthDomain, soup_auth_domain, G_TYPE_OBJECT)
73 
74 static void
75 soup_auth_domain_init (SoupAuthDomain *domain)
76 {
77 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
78 
79 	priv->paths = soup_path_map_new (NULL);
80 }
81 
82 static void
soup_auth_domain_finalize(GObject * object)83 soup_auth_domain_finalize (GObject *object)
84 {
85 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (SOUP_AUTH_DOMAIN (object));
86 
87 	g_free (priv->realm);
88 	soup_path_map_free (priv->paths);
89 
90 	if (priv->filter_dnotify)
91 		priv->filter_dnotify (priv->filter_data);
92 	if (priv->auth_dnotify)
93 		priv->auth_dnotify (priv->auth_data);
94 
95 	G_OBJECT_CLASS (soup_auth_domain_parent_class)->finalize (object);
96 }
97 
98 static void
soup_auth_domain_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)99 soup_auth_domain_set_property (GObject *object, guint prop_id,
100 			       const GValue *value, GParamSpec *pspec)
101 {
102 	SoupAuthDomain *auth_domain = SOUP_AUTH_DOMAIN (object);
103 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (auth_domain);
104 
105 	switch (prop_id) {
106 	case PROP_REALM:
107 		g_free (priv->realm);
108 		priv->realm = g_value_dup_string (value);
109 		break;
110 	case PROP_PROXY:
111 		priv->proxy = g_value_get_boolean (value);
112 		break;
113 	case PROP_ADD_PATH:
114 		soup_auth_domain_add_path (auth_domain,
115 					   g_value_get_string (value));
116 		break;
117 	case PROP_REMOVE_PATH:
118 		soup_auth_domain_remove_path (auth_domain,
119 					      g_value_get_string (value));
120 		break;
121 	case PROP_FILTER:
122 		priv->filter = g_value_get_pointer (value);
123 		break;
124 	case PROP_FILTER_DATA:
125 		if (priv->filter_dnotify) {
126 			priv->filter_dnotify (priv->filter_data);
127 			priv->filter_dnotify = NULL;
128 		}
129 		priv->filter_data = g_value_get_pointer (value);
130 		break;
131 	case PROP_GENERIC_AUTH_CALLBACK:
132 		priv->auth_callback = g_value_get_pointer (value);
133 		break;
134 	case PROP_GENERIC_AUTH_DATA:
135 		if (priv->auth_dnotify) {
136 			priv->auth_dnotify (priv->auth_data);
137 			priv->auth_dnotify = NULL;
138 		}
139 		priv->auth_data = g_value_get_pointer (value);
140 		break;
141 	default:
142 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
143 		break;
144 	}
145 }
146 
147 static void
soup_auth_domain_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)148 soup_auth_domain_get_property (GObject *object, guint prop_id,
149 			       GValue *value, GParamSpec *pspec)
150 {
151 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (SOUP_AUTH_DOMAIN (object));
152 
153 	switch (prop_id) {
154 	case PROP_REALM:
155 		g_value_set_string (value, priv->realm);
156 		break;
157 	case PROP_PROXY:
158 		g_value_set_boolean (value, priv->proxy);
159 		break;
160 	case PROP_FILTER:
161 		g_value_set_pointer (value, priv->filter);
162 		break;
163 	case PROP_FILTER_DATA:
164 		g_value_set_pointer (value, priv->filter_data);
165 		break;
166 	case PROP_GENERIC_AUTH_CALLBACK:
167 		g_value_set_pointer (value, priv->auth_callback);
168 		break;
169 	case PROP_GENERIC_AUTH_DATA:
170 		g_value_set_pointer (value, priv->auth_data);
171 		break;
172 	default:
173 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174 		break;
175 	}
176 }
177 
178 static void
soup_auth_domain_class_init(SoupAuthDomainClass * auth_domain_class)179 soup_auth_domain_class_init (SoupAuthDomainClass *auth_domain_class)
180 {
181 	GObjectClass *object_class = G_OBJECT_CLASS (auth_domain_class);
182 
183 	object_class->finalize = soup_auth_domain_finalize;
184 	object_class->set_property = soup_auth_domain_set_property;
185 	object_class->get_property = soup_auth_domain_get_property;
186 
187 	/**
188 	 * SOUP_AUTH_DOMAIN_REALM:
189 	 *
190 	 * Alias for the #SoupAuthDomain:realm property. (The realm of
191 	 * this auth domain.)
192 	 **/
193 	g_object_class_install_property (
194 		object_class, PROP_REALM,
195 		g_param_spec_string (SOUP_AUTH_DOMAIN_REALM,
196 				     "Realm",
197 				     "The realm of this auth domain",
198 				     NULL,
199 				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
200 				     G_PARAM_STATIC_STRINGS));
201 	/**
202 	 * SOUP_AUTH_DOMAIN_PROXY:
203 	 *
204 	 * Alias for the #SoupAuthDomain:proxy property. (Whether or
205 	 * not this is a proxy auth domain.)
206 	 **/
207 	g_object_class_install_property (
208 		object_class, PROP_PROXY,
209 		g_param_spec_boolean (SOUP_AUTH_DOMAIN_PROXY,
210 				      "Proxy",
211 				      "Whether or not this is a proxy auth domain",
212 				      FALSE,
213 				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
214 				      G_PARAM_STATIC_STRINGS));
215 	/**
216 	 * SOUP_AUTH_DOMAIN_ADD_PATH:
217 	 *
218 	 * Alias for the #SoupAuthDomain:add-path property. (Shortcut
219 	 * for calling soup_auth_domain_add_path().)
220 	 **/
221 	g_object_class_install_property (
222 		object_class, PROP_ADD_PATH,
223 		g_param_spec_string (SOUP_AUTH_DOMAIN_ADD_PATH,
224 				     "Add a path",
225 				     "Add a path covered by this auth domain",
226 				     NULL,
227 				     G_PARAM_WRITABLE |
228 				     G_PARAM_STATIC_STRINGS));
229 	/**
230 	 * SOUP_AUTH_DOMAIN_REMOVE_PATH:
231 	 *
232 	 * Alias for the #SoupAuthDomain:remove-path property.
233 	 * (Shortcut for calling soup_auth_domain_remove_path().)
234 	 **/
235 	g_object_class_install_property (
236 		object_class, PROP_REMOVE_PATH,
237 		g_param_spec_string (SOUP_AUTH_DOMAIN_REMOVE_PATH,
238 				     "Remove a path",
239 				     "Remove a path covered by this auth domain",
240 				     NULL,
241 				     G_PARAM_WRITABLE |
242 				     G_PARAM_STATIC_STRINGS));
243 	/**
244 	 * SOUP_AUTH_DOMAIN_FILTER:
245 	 *
246 	 * Alias for the #SoupAuthDomain:filter property. (The
247 	 * #SoupAuthDomainFilter for the domain.)
248 	 **/
249 	/**
250 	 * SoupAuthDomain:filter: (type SoupAuthDomainFilter)
251 	 *
252 	 * The #SoupAuthDomainFilter for the domain
253 	 */
254 	g_object_class_install_property (
255 		object_class, PROP_FILTER,
256 		g_param_spec_pointer (SOUP_AUTH_DOMAIN_FILTER,
257 				      "Filter",
258 				      "A filter for deciding whether or not to require authentication",
259 				      G_PARAM_READWRITE |
260 				      G_PARAM_STATIC_STRINGS));
261 	/**
262 	 * SOUP_AUTH_DOMAIN_FILTER_DATA:
263 	 *
264 	 * Alias for the #SoupAuthDomain:filter-data property. (Data
265 	 * to pass to the #SoupAuthDomainFilter.)
266 	 **/
267 	/**
268 	 * SoupAuthDomain:generic-auth-callback: (type SoupAuthDomainGenericAuthCallback)
269 	 *
270 	 * The #SoupAuthDomainGenericAuthCallback for the domain
271 	 */
272 	g_object_class_install_property (
273 		object_class, PROP_FILTER_DATA,
274 		g_param_spec_pointer (SOUP_AUTH_DOMAIN_FILTER_DATA,
275 				      "Filter data",
276 				      "Data to pass to filter",
277 				      G_PARAM_READWRITE |
278 				      G_PARAM_STATIC_STRINGS));
279 	/**
280 	 * SOUP_AUTH_DOMAIN_GENERIC_AUTH_CALLBACK:
281 	 *
282 	 * Alias for the #SoupAuthDomain:generic-auth-callback property.
283 	 * (The #SoupAuthDomainGenericAuthCallback.)
284 	 **/
285 	g_object_class_install_property (
286 		object_class, PROP_GENERIC_AUTH_CALLBACK,
287 		g_param_spec_pointer (SOUP_AUTH_DOMAIN_GENERIC_AUTH_CALLBACK,
288 				      "Generic authentication callback",
289 				      "An authentication callback that can be used with any SoupAuthDomain subclass",
290 				      G_PARAM_READWRITE |
291 				      G_PARAM_STATIC_STRINGS));
292 	/**
293 	 * SOUP_AUTH_DOMAIN_GENERIC_AUTH_DATA:
294 	 *
295 	 * Alias for the #SoupAuthDomain:generic-auth-data property.
296 	 * (The data to pass to the #SoupAuthDomainGenericAuthCallback.)
297 	 **/
298 	g_object_class_install_property (
299 		object_class, PROP_GENERIC_AUTH_DATA,
300 		g_param_spec_pointer (SOUP_AUTH_DOMAIN_GENERIC_AUTH_DATA,
301 				      "Authentication callback data",
302 				      "Data to pass to auth callback",
303 				      G_PARAM_READWRITE |
304 				      G_PARAM_STATIC_STRINGS));
305 }
306 
307 /**
308  * soup_auth_domain_add_path:
309  * @domain: a #SoupAuthDomain
310  * @path: the path to add to @domain
311  *
312  * Adds @path to @domain, such that requests under @path on @domain's
313  * server will require authentication (unless overridden by
314  * soup_auth_domain_remove_path() or soup_auth_domain_set_filter()).
315  *
316  * You can also add paths by setting the %SOUP_AUTH_DOMAIN_ADD_PATH
317  * property, which can also be used to add one or more paths at
318  * construct time.
319  **/
320 void
soup_auth_domain_add_path(SoupAuthDomain * domain,const char * path)321 soup_auth_domain_add_path (SoupAuthDomain *domain, const char *path)
322 {
323 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
324 
325 	/* "" should not match "*" */
326 	if (!*path)
327 		path = "/";
328 
329 	soup_path_map_add (priv->paths, path, GINT_TO_POINTER (TRUE));
330 }
331 
332 /**
333  * soup_auth_domain_remove_path:
334  * @domain: a #SoupAuthDomain
335  * @path: the path to remove from @domain
336  *
337  * Removes @path from @domain, such that requests under @path on
338  * @domain's server will NOT require authentication.
339  *
340  * This is not simply an undo-er for soup_auth_domain_add_path(); it
341  * can be used to "carve out" a subtree that does not require
342  * authentication inside a hierarchy that does. Note also that unlike
343  * with soup_auth_domain_add_path(), this cannot be overridden by
344  * adding a filter, as filters can only bypass authentication that
345  * would otherwise be required, not require it where it would
346  * otherwise be unnecessary.
347  *
348  * You can also remove paths by setting the
349  * %SOUP_AUTH_DOMAIN_REMOVE_PATH property, which can also be used to
350  * remove one or more paths at construct time.
351  **/
352 void
soup_auth_domain_remove_path(SoupAuthDomain * domain,const char * path)353 soup_auth_domain_remove_path (SoupAuthDomain *domain, const char *path)
354 {
355 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
356 
357 	/* "" should not match "*" */
358 	if (!*path)
359 		path = "/";
360 
361 	soup_path_map_add (priv->paths, path, GINT_TO_POINTER (FALSE));
362 }
363 
364 /**
365  * SoupAuthDomainFilter:
366  * @domain: a #SoupAuthDomain
367  * @msg: a #SoupMessage
368  * @user_data: the data passed to soup_auth_domain_set_filter()
369  *
370  * The prototype for a #SoupAuthDomain filter; see
371  * soup_auth_domain_set_filter() for details.
372  *
373  * Return value: %TRUE if @msg requires authentication, %FALSE if not.
374  **/
375 
376 /**
377  * soup_auth_domain_set_filter:
378  * @domain: a #SoupAuthDomain
379  * @filter: the auth filter for @domain
380  * @filter_data: data to pass to @filter
381  * @dnotify: destroy notifier to free @filter_data when @domain
382  * is destroyed
383  *
384  * Adds @filter as an authentication filter to @domain. The filter
385  * gets a chance to bypass authentication for certain requests that
386  * would otherwise require it. Eg, it might check the message's path
387  * in some way that is too complicated to do via the other methods, or
388  * it might check the message's method, and allow GETs but not PUTs.
389  *
390  * The filter function returns %TRUE if the request should still
391  * require authentication, or %FALSE if authentication is unnecessary
392  * for this request.
393  *
394  * To help prevent security holes, your filter should return %TRUE by
395  * default, and only return %FALSE under specifically-tested
396  * circumstances, rather than the other way around. Eg, in the example
397  * above, where you want to authenticate PUTs but not GETs, you should
398  * check if the method is GET and return %FALSE in that case, and then
399  * return %TRUE for all other methods (rather than returning %TRUE for
400  * PUT and %FALSE for all other methods). This way if it turned out
401  * (now or later) that some paths supported additional methods besides
402  * GET and PUT, those methods would default to being NOT allowed for
403  * unauthenticated users.
404  *
405  * You can also set the filter by setting the %SOUP_AUTH_DOMAIN_FILTER
406  * and %SOUP_AUTH_DOMAIN_FILTER_DATA properties, which can also be
407  * used to set the filter at construct time.
408  **/
409 void
soup_auth_domain_set_filter(SoupAuthDomain * domain,SoupAuthDomainFilter filter,gpointer filter_data,GDestroyNotify dnotify)410 soup_auth_domain_set_filter (SoupAuthDomain *domain,
411 			     SoupAuthDomainFilter filter,
412 			     gpointer        filter_data,
413 			     GDestroyNotify  dnotify)
414 {
415 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
416 
417 	if (priv->filter_dnotify)
418 		priv->filter_dnotify (priv->filter_data);
419 
420 	priv->filter = filter;
421 	priv->filter_data = filter_data;
422 	priv->filter_dnotify = dnotify;
423 
424 	g_object_notify (G_OBJECT (domain), SOUP_AUTH_DOMAIN_FILTER);
425 	g_object_notify (G_OBJECT (domain), SOUP_AUTH_DOMAIN_FILTER_DATA);
426 }
427 
428 /**
429  * soup_auth_domain_get_realm:
430  * @domain: a #SoupAuthDomain
431  *
432  * Gets the realm name associated with @domain
433  *
434  * Return value: @domain's realm
435  **/
436 const char *
soup_auth_domain_get_realm(SoupAuthDomain * domain)437 soup_auth_domain_get_realm (SoupAuthDomain *domain)
438 {
439 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
440 
441 	return priv->realm;
442 }
443 
444 /**
445  * SoupAuthDomainGenericAuthCallback:
446  * @domain: a #SoupAuthDomain
447  * @msg: the #SoupMessage being authenticated
448  * @username: the username from @msg
449  * @user_data: the data passed to
450  * soup_auth_domain_set_generic_auth_callback()
451  *
452  * The prototype for a #SoupAuthDomain generic authentication callback.
453  *
454  * The callback should look up the user's password, call
455  * soup_auth_domain_check_password(), and use the return value from
456  * that method as its own return value.
457  *
458  * In general, for security reasons, it is preferable to use the
459  * auth-domain-specific auth callbacks (eg,
460  * #SoupAuthDomainBasicAuthCallback and
461  * #SoupAuthDomainDigestAuthCallback), because they don't require
462  * keeping a cleartext password database. Most users will use the same
463  * password for many different sites, meaning if any site with a
464  * cleartext password database is compromised, accounts on other
465  * servers might be compromised as well. For many of the cases where
466  * #SoupServer is used, this is not really relevant, but it may still
467  * be worth considering.
468  *
469  * Return value: %TRUE if @msg is authenticated, %FALSE if not.
470  **/
471 
472 /**
473  * soup_auth_domain_set_generic_auth_callback:
474  * @domain: a #SoupAuthDomain
475  * @auth_callback: the auth callback
476  * @auth_data: data to pass to @auth_callback
477  * @dnotify: destroy notifier to free @auth_data when @domain
478  * is destroyed
479  *
480  * Sets @auth_callback as an authentication-handling callback for
481  * @domain. Whenever a request comes in to @domain which cannot be
482  * authenticated via a domain-specific auth callback (eg,
483  * #SoupAuthDomainDigestAuthCallback), the generic auth callback
484  * will be invoked. See #SoupAuthDomainGenericAuthCallback for information
485  * on what the callback should do.
486  **/
487 void
soup_auth_domain_set_generic_auth_callback(SoupAuthDomain * domain,SoupAuthDomainGenericAuthCallback auth_callback,gpointer auth_data,GDestroyNotify dnotify)488 soup_auth_domain_set_generic_auth_callback (SoupAuthDomain *domain,
489 					    SoupAuthDomainGenericAuthCallback auth_callback,
490 					    gpointer        auth_data,
491 					    GDestroyNotify  dnotify)
492 {
493 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
494 
495 	if (priv->auth_dnotify)
496 		priv->auth_dnotify (priv->auth_data);
497 
498 	priv->auth_callback = auth_callback;
499 	priv->auth_data = auth_data;
500 	priv->auth_dnotify = dnotify;
501 
502 	g_object_notify (G_OBJECT (domain), SOUP_AUTH_DOMAIN_GENERIC_AUTH_CALLBACK);
503 	g_object_notify (G_OBJECT (domain), SOUP_AUTH_DOMAIN_GENERIC_AUTH_DATA);
504 }
505 
506 gboolean
soup_auth_domain_try_generic_auth_callback(SoupAuthDomain * domain,SoupMessage * msg,const char * username)507 soup_auth_domain_try_generic_auth_callback (SoupAuthDomain *domain,
508 					    SoupMessage    *msg,
509 					    const char     *username)
510 {
511 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
512 
513 	if (priv->auth_callback)
514 		return priv->auth_callback (domain, msg, username, priv->auth_data);
515 	else
516 		return FALSE;
517 }
518 
519 /**
520  * soup_auth_domain_check_password:
521  * @domain: a #SoupAuthDomain
522  * @msg: a #SoupMessage
523  * @username: a username
524  * @password: a password
525  *
526  * Checks if @msg authenticates to @domain via @username and
527  * @password. This would normally be called from a
528  * #SoupAuthDomainGenericAuthCallback.
529  *
530  * Return value: whether or not the message is authenticated
531  **/
532 gboolean
soup_auth_domain_check_password(SoupAuthDomain * domain,SoupMessage * msg,const char * username,const char * password)533 soup_auth_domain_check_password (SoupAuthDomain *domain,
534 				 SoupMessage    *msg,
535 				 const char     *username,
536 				 const char     *password)
537 {
538 	return SOUP_AUTH_DOMAIN_GET_CLASS (domain)->check_password (domain, msg,
539 								    username,
540 								    password);
541 }
542 
543 /**
544  * soup_auth_domain_covers:
545  * @domain: a #SoupAuthDomain
546  * @msg: a #SoupMessage
547  *
548  * Checks if @domain requires @msg to be authenticated (according to
549  * its paths and filter function). This does not actually look at
550  * whether @msg <emphasis>is</emphasis> authenticated, merely whether
551  * or not it needs to be.
552  *
553  * This is used by #SoupServer internally and is probably of no use to
554  * anyone else.
555  *
556  * Return value: %TRUE if @domain requires @msg to be authenticated
557  **/
558 gboolean
soup_auth_domain_covers(SoupAuthDomain * domain,SoupMessage * msg)559 soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg)
560 {
561 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
562 	const char *path;
563 
564 	if (!priv->proxy) {
565 		path = soup_message_get_uri (msg)->path;
566 		if (!soup_path_map_lookup (priv->paths, path))
567 			return FALSE;
568 	}
569 
570 	if (priv->filter && !priv->filter (domain, msg, priv->filter_data))
571 		return FALSE;
572 	else
573 		return TRUE;
574 }
575 
576 /**
577  * soup_auth_domain_accepts:
578  * @domain: a #SoupAuthDomain
579  * @msg: a #SoupMessage
580  *
581  * Checks if @msg contains appropriate authorization for @domain to
582  * accept it. Mirroring soup_auth_domain_covers(), this does not check
583  * whether or not @domain <emphasis>cares</emphasis> if @msg is
584  * authorized.
585  *
586  * This is used by #SoupServer internally and is probably of no use to
587  * anyone else.
588  *
589  * Return value: (nullable): the username that @msg has authenticated
590  * as, if in fact it has authenticated. %NULL otherwise.
591  **/
592 char *
soup_auth_domain_accepts(SoupAuthDomain * domain,SoupMessage * msg)593 soup_auth_domain_accepts (SoupAuthDomain *domain, SoupMessage *msg)
594 {
595 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
596 	const char *header;
597 
598 	header = soup_message_headers_get_one (msg->request_headers,
599 					       priv->proxy ?
600 					       "Proxy-Authorization" :
601 					       "Authorization");
602 	if (!header)
603 		return NULL;
604 	return SOUP_AUTH_DOMAIN_GET_CLASS (domain)->accepts (domain, msg, header);
605 }
606 
607 /**
608  * soup_auth_domain_challenge: (virtual challenge)
609  * @domain: a #SoupAuthDomain
610  * @msg: a #SoupMessage
611  *
612  * Adds a "WWW-Authenticate" or "Proxy-Authenticate" header to @msg,
613  * requesting that the client authenticate, and sets @msg's status
614  * accordingly.
615  *
616  * This is used by #SoupServer internally and is probably of no use to
617  * anyone else.
618  **/
619 void
soup_auth_domain_challenge(SoupAuthDomain * domain,SoupMessage * msg)620 soup_auth_domain_challenge (SoupAuthDomain *domain, SoupMessage *msg)
621 {
622 	SoupAuthDomainPrivate *priv = soup_auth_domain_get_instance_private (domain);
623 	char *challenge;
624 
625 	challenge = SOUP_AUTH_DOMAIN_GET_CLASS (domain)->challenge (domain, msg);
626 	soup_message_set_status (msg, priv->proxy ?
627 				 SOUP_STATUS_PROXY_UNAUTHORIZED :
628 				 SOUP_STATUS_UNAUTHORIZED);
629 	soup_message_headers_append (msg->response_headers,
630 				     priv->proxy ?
631 				     "Proxy-Authenticate" :
632 				     "WWW-Authenticate",
633 				     challenge);
634 	g_free (challenge);
635 }
636