1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-auth-domain-basic.c: HTTP Basic Authentication (server-side)
5 * Copyright (C) 2007 Novell, Inc.
14 #include "soup-auth-domain-basic.h"
15 #include "soup-headers.h"
16 #include "soup-marshal.h"
17 #include "soup-message.h"
20 * SECTION:soup-auth-domain-basic
21 * @short_description: Server-side "Basic" authentication
23 * #SoupAuthDomainBasic handles the server side of HTTP "Basic" (ie,
24 * cleartext password) authentication.
37 SoupAuthDomainBasicAuthCallback auth_callback;
39 GDestroyNotify auth_dnotify;
40 } SoupAuthDomainBasicPrivate;
42 #define SOUP_AUTH_DOMAIN_BASIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_DOMAIN_BASIC, SoupAuthDomainBasicPrivate))
44 G_DEFINE_TYPE (SoupAuthDomainBasic, soup_auth_domain_basic, SOUP_TYPE_AUTH_DOMAIN)
46 static char *accepts (SoupAuthDomain *domain,
49 static char *challenge (SoupAuthDomain *domain,
51 static gboolean check_password (SoupAuthDomain *domain,
54 const char *password);
56 static void set_property (GObject *object, guint prop_id,
57 const GValue *value, GParamSpec *pspec);
58 static void get_property (GObject *object, guint prop_id,
59 GValue *value, GParamSpec *pspec);
62 soup_auth_domain_basic_init (SoupAuthDomainBasic *basic)
67 finalize (GObject *object)
69 SoupAuthDomainBasicPrivate *priv =
70 SOUP_AUTH_DOMAIN_BASIC_GET_PRIVATE (object);
72 if (priv->auth_dnotify)
73 priv->auth_dnotify (priv->auth_data);
75 G_OBJECT_CLASS (soup_auth_domain_basic_parent_class)->finalize (object);
79 soup_auth_domain_basic_class_init (SoupAuthDomainBasicClass *basic_class)
81 SoupAuthDomainClass *auth_domain_class =
82 SOUP_AUTH_DOMAIN_CLASS (basic_class);
83 GObjectClass *object_class = G_OBJECT_CLASS (basic_class);
85 g_type_class_add_private (basic_class, sizeof (SoupAuthDomainBasicPrivate));
87 auth_domain_class->accepts = accepts;
88 auth_domain_class->challenge = challenge;
89 auth_domain_class->check_password = check_password;
91 object_class->finalize = finalize;
92 object_class->set_property = set_property;
93 object_class->get_property = get_property;
96 * SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK:
98 * Alias for the #SoupAuthDomainBasic:auth-callback property.
99 * (The #SoupAuthDomainBasicAuthCallback.)
101 g_object_class_install_property (
102 object_class, PROP_AUTH_CALLBACK,
103 g_param_spec_pointer (SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK,
104 "Authentication callback",
105 "Password-checking callback",
108 * SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA:
110 * Alias for the #SoupAuthDomainBasic:auth-data property.
111 * (The data to pass to the #SoupAuthDomainBasicAuthCallback.)
113 g_object_class_install_property (
114 object_class, PROP_AUTH_DATA,
115 g_param_spec_pointer (SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA,
116 "Authentication callback data",
117 "Data to pass to authentication callback",
122 set_property (GObject *object, guint prop_id,
123 const GValue *value, GParamSpec *pspec)
125 SoupAuthDomainBasicPrivate *priv =
126 SOUP_AUTH_DOMAIN_BASIC_GET_PRIVATE (object);
129 case PROP_AUTH_CALLBACK:
130 priv->auth_callback = g_value_get_pointer (value);
133 if (priv->auth_dnotify) {
134 priv->auth_dnotify (priv->auth_data);
135 priv->auth_dnotify = NULL;
137 priv->auth_data = g_value_get_pointer (value);
140 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
146 get_property (GObject *object, guint prop_id,
147 GValue *value, GParamSpec *pspec)
149 SoupAuthDomainBasicPrivate *priv =
150 SOUP_AUTH_DOMAIN_BASIC_GET_PRIVATE (object);
153 case PROP_AUTH_CALLBACK:
154 g_value_set_pointer (value, priv->auth_callback);
157 g_value_set_pointer (value, priv->auth_data);
160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
166 * soup_auth_domain_basic_new:
167 * @optname1: name of first option, or %NULL
168 * @...: option name/value pairs
170 * Creates a #SoupAuthDomainBasic. You must set the
171 * %SOUP_AUTH_DOMAIN_REALM parameter, to indicate the realm name to be
172 * returned with the authentication challenge to the client. Other
173 * parameters are optional.
175 * Return value: the new #SoupAuthDomain
178 soup_auth_domain_basic_new (const char *optname1, ...)
180 SoupAuthDomain *domain;
183 va_start (ap, optname1);
184 domain = (SoupAuthDomain *)g_object_new_valist (SOUP_TYPE_AUTH_DOMAIN_BASIC,
188 g_return_val_if_fail (soup_auth_domain_get_realm (domain) != NULL, NULL);
194 * SoupAuthDomainBasicAuthCallback:
195 * @domain: the domain
196 * @msg: the message being authenticated
197 * @username: the username provided by the client
198 * @password: the password provided by the client
199 * @user_data: the data passed to soup_auth_domain_basic_set_auth_callback()
201 * Callback used by #SoupAuthDomainBasic for authentication purposes.
202 * The application should verify that @username and @password and valid
203 * and return %TRUE or %FALSE.
205 * If you are maintaining your own password database (rather than
206 * using the password to authenticate against some other system like
207 * PAM or a remote server), you should make sure you know what you are
208 * doing. In particular, don't store cleartext passwords, or
209 * easily-computed hashes of cleartext passwords, even if you don't
210 * care that much about the security of your server, because users
211 * will frequently use the same password for multiple sites, and so
212 * compromising any site with a cleartext (or easily-cracked) password
213 * database may give attackers access to other more-interesting sites
216 * Return value: %TRUE if @username and @password are valid
220 * soup_auth_domain_basic_set_auth_callback:
221 * @domain: the domain
222 * @callback: the callback
223 * @user_data: data to pass to @auth_callback
224 * @dnotify: destroy notifier to free @user_data when @domain
227 * Sets the callback that @domain will use to authenticate incoming
228 * requests. For each request containing authorization, @domain will
229 * invoke the callback, and then either accept or reject the request
230 * based on @callback's return value.
232 * You can also set the auth callback by setting the
233 * %SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK and
234 * %SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA properties, which can also be
235 * used to set the callback at construct time.
238 soup_auth_domain_basic_set_auth_callback (SoupAuthDomain *domain,
239 SoupAuthDomainBasicAuthCallback callback,
241 GDestroyNotify dnotify)
243 SoupAuthDomainBasicPrivate *priv =
244 SOUP_AUTH_DOMAIN_BASIC_GET_PRIVATE (domain);
246 if (priv->auth_dnotify)
247 priv->auth_dnotify (priv->auth_data);
249 priv->auth_callback = callback;
250 priv->auth_data = user_data;
251 priv->auth_dnotify = dnotify;
253 g_object_notify (G_OBJECT (domain), SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK);
254 g_object_notify (G_OBJECT (domain), SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA);
260 memset (pw, 0, strlen (pw));
265 parse_basic (SoupMessage *msg, const char *header,
266 char **username, char **password)
268 char *decoded, *colon;
271 if (!header || (strncmp (header, "Basic ", 6) != 0))
274 decoded = (char *)g_base64_decode (header + 6, &len);
278 colon = memchr (decoded, ':', len);
284 plen = len - (colon - decoded) - 1;
286 *password = g_strndup (colon + 1, plen);
287 memset (colon + 1, 0, plen);
293 accepts (SoupAuthDomain *domain, SoupMessage *msg, const char *header)
295 SoupAuthDomainBasicPrivate *priv =
296 SOUP_AUTH_DOMAIN_BASIC_GET_PRIVATE (domain);
297 char *username, *password;
300 if (!parse_basic (msg, header, &username, &password))
303 if (priv->auth_callback) {
304 ok = priv->auth_callback (domain, msg, username, password,
307 ok = soup_auth_domain_try_generic_auth_callback (
308 domain, msg, username);
322 challenge (SoupAuthDomain *domain, SoupMessage *msg)
326 challenge = g_string_new ("Basic ");
327 soup_header_g_string_append_param (challenge, "realm", soup_auth_domain_get_realm (domain));
328 return g_string_free (challenge, FALSE);
332 check_password (SoupAuthDomain *domain,
334 const char *username,
335 const char *password)
338 char *msg_username, *msg_password;
341 header = soup_message_headers_get_one (msg->request_headers,
343 if (!parse_basic (msg, header, &msg_username, &msg_password))
346 ok = (!strcmp (username, msg_username) &&
347 !strcmp (password, msg_password));
348 g_free (msg_username);
349 pw_free (msg_password);