soup_header_param_destroy_hash (tokens);
}
+static GSList *
+basic_pspace_func (SoupAuth *auth, const SoupUri *source_uri)
+{
+ char *space, *p;
+
+ space = g_strdup (source_uri->path);
+
+ /* Strip query and filename component */
+ p = strrchr (space, '/');
+ if (p && p != space && p[1])
+ *p = '\0';
+
+ return g_slist_prepend (NULL, space);
+}
+
static void
basic_init_func (SoupAuth *auth, const SoupUri *uri)
{
user_pass = g_strdup_printf ("%s:%s", uri->user, uri->passwd);
basic->token = soup_base64_encode (user_pass, strlen (user_pass));
g_free (user_pass);
+
+ auth->authenticated = TRUE;
+}
+
+static gboolean
+basic_invalidate_func (SoupAuth *auth)
+{
+ SoupAuthBasic *basic = (SoupAuthBasic *) auth;
+
+ g_free (basic->token);
+ basic->token = NULL;
+ auth->authenticated = FALSE;
+
+ return TRUE;
}
static void
basic = g_new0 (SoupAuthBasic, 1);
auth = (SoupAuth *) basic;
auth->type = SOUP_AUTH_TYPE_BASIC;
+ auth->authenticated = FALSE;
auth->parse_func = basic_parse_func;
auth->init_func = basic_init_func;
+ auth->invalidate_func = basic_invalidate_func;
+ auth->pspace_func = basic_pspace_func;
auth->auth_func = basic_auth_func;
auth->free_func = basic_free;
char *nonce;
QOPType qop_options;
AlgorithmType algorithm;
+ char *domain;
/* These are generated by the client */
char *cnonce;
auth->realm = soup_header_param_copy_token (tokens, "realm");
digest->nonce = soup_header_param_copy_token (tokens, "nonce");
+ digest->domain = soup_header_param_copy_token (tokens, "domain");
tmp = soup_header_param_copy_token (tokens, "qop");
ptr = tmp;
soup_header_param_destroy_hash (tokens);
}
+static GSList *
+digest_pspace_func (SoupAuth *auth, const SoupUri *source_uri)
+{
+ SoupAuthDigest *digest = (SoupAuthDigest *) auth;
+ GSList *space = NULL;
+ SoupUri *uri;
+ char *domain, *d, *lasts, *dir, *slash;
+
+ if (!digest->domain || !*digest->domain) {
+ /* If no domain directive, the protection space is the
+ * whole server.
+ */
+ return g_slist_prepend (NULL, g_strdup (""));
+ }
+
+ domain = g_strdup (digest->domain);
+ for (d = strtok_r (domain, " ", &lasts); d; d = strtok_r (NULL, " ", &lasts)) {
+ if (*d == '/')
+ dir = g_strdup (d);
+ else {
+ uri = soup_uri_new (d);
+ if (uri && uri->protocol == source_uri->protocol &&
+ uri->port == source_uri->port &&
+ !strcmp (uri->host, source_uri->host))
+ dir = g_strdup (uri->path);
+ else
+ dir = NULL;
+ if (uri)
+ soup_uri_free (uri);
+ }
+
+ if (dir) {
+ slash = strrchr (dir, '/');
+ if (slash && !slash[1])
+ *slash = '\0';
+
+ space = g_slist_prepend (space, dir);
+ }
+ }
+ g_free (domain);
+
+ return space;
+}
+
static void
digest_init_func (SoupAuth *auth, const SoupUri *uri)
{
/* hexify A1 */
md5_final (&ctx, d);
digest_hex (d, digest->hex_a1);
+
+ auth->authenticated = TRUE;
+}
+
+static gboolean
+digest_invalidate_func (SoupAuth *auth)
+{
+ /* If we failed, we need to get a new nonce from the server
+ * next time, so this can't be reused.
+ */
+ return FALSE;
}
static void
SoupAuthDigest *digest = (SoupAuthDigest *) auth;
g_free (digest->user);
+ g_free (digest->domain);
g_free (digest->nonce);
g_free (digest->cnonce);
auth = (SoupAuth *) digest;
auth->type = SOUP_AUTH_TYPE_DIGEST;
+ auth->authenticated = FALSE;
auth->parse_func = digest_parse_func;
auth->init_func = digest_init_func;
+ auth->invalidate_func = digest_invalidate_func;
+ auth->pspace_func = digest_pspace_func;
auth->auth_func = digest_auth_func;
auth->free_func = digest_free;
ntlm_auth (SoupAuth *sa, SoupMessage *msg)
{
SoupAuthNTLM *auth = (SoupAuthNTLM *) sa;
- gchar *ret;
+ char *ret;
- if (sa->status == SOUP_AUTH_STATUS_PENDING)
+ if (!sa->authenticated)
return soup_ntlm_request ();
/* Otherwise, return the response; but only once */
ret = auth->response;
auth->response = NULL;
-
return ret;
}
g_strstrip (auth->header);
}
+static GSList *
+ntlm_pspace (SoupAuth *auth, const SoupUri *source_uri)
+{
+ /* The protection space is the whole server. */
+ return g_slist_prepend (NULL, g_strdup (""));
+}
+
static void
ntlm_init (SoupAuth *sa, const SoupUri *uri)
{
SoupAuthNTLM *auth = (SoupAuthNTLM *) sa;
gchar *host, *domain, *nonce;
- if (strlen (auth->header) < sizeof ("NTLM"))
+ if (!auth->header || strlen (auth->header) < sizeof ("NTLM"))
return;
if (auth->response)
g_free (host);
g_free (domain);
- /* Set this now so that if the server returns 401,
- * soup will fail instead of looping (since that
- * probably means the password was incorrect).
- */
- sa->status = SOUP_AUTH_STATUS_SUCCESSFUL;
+ g_free (auth->header);
+ auth->header = NULL;
+
+ sa->authenticated = TRUE;
+}
+
+static gboolean
+ntlm_invalidate (SoupAuth *sa)
+{
+ SoupAuthNTLM *auth = (SoupAuthNTLM *) sa;
+ g_free (auth->response);
+ auth->response = NULL;
g_free (auth->header);
auth->header = NULL;
+
+ sa->authenticated = FALSE;
+ return TRUE;
}
static void
g_free (auth);
}
-static SoupAuth *
-ntlm_new (void)
+SoupAuth *
+soup_auth_new_ntlm (void)
{
SoupAuthNTLM *auth;
auth = g_new0 (SoupAuthNTLM, 1);
auth->auth.type = SOUP_AUTH_TYPE_NTLM;
+ auth->auth.authenticated = FALSE;
+ auth->auth.realm = g_strdup ("");
auth->auth.parse_func = ntlm_parse;
auth->auth.init_func = ntlm_init;
+ auth->auth.invalidate_func = ntlm_invalidate;
+ auth->auth.pspace_func = ntlm_pspace;
auth->auth.auth_func = ntlm_auth;
auth->auth.free_func = ntlm_free;
* Generic Authentication Interface
*/
-SoupAuth *
-soup_auth_lookup (SoupContext *ctx)
-{
- GHashTable *auth_hash = ctx->server->valid_auths;
- SoupAuth *ret = NULL;
- gchar *mypath, *dir;
-
- if (!auth_hash) return NULL;
-
- mypath = g_strdup (ctx->uri->path);
- dir = mypath;
-
- do {
- ret = g_hash_table_lookup (auth_hash, mypath);
- if (ret) break;
-
- dir = strrchr (mypath, '/');
- if (dir) *dir = '\0';
- } while (dir);
-
- g_free (mypath);
- return ret;
-}
-
-void
-soup_auth_invalidate (SoupAuth *auth, SoupContext *ctx)
-{
- SoupHost *server;
- const SoupUri *uri;
- SoupAuth *old_auth;
- char *old_path;
-
- g_return_if_fail (ctx != NULL);
- g_return_if_fail (auth != NULL);
-
- server = ctx->server;
-
- if (!server->valid_auths)
- return;
-
- uri = soup_context_get_uri (ctx);
- if (g_hash_table_lookup_extended (server->valid_auths,
- uri->path,
- (gpointer *) &old_path,
- (gpointer *) &old_auth)) {
- g_hash_table_remove (server->valid_auths, old_path);
- g_free (old_path);
- soup_auth_free (old_auth);
- }
-}
-
-void
-soup_auth_set_context (SoupAuth *auth, SoupContext *ctx)
-{
- SoupHost *server;
- SoupAuth *old_auth = NULL;
- gchar *old_path;
- const SoupUri *uri;
-
- g_return_if_fail (ctx != NULL);
- g_return_if_fail (auth != NULL);
-
- server = ctx->server;
- uri = soup_context_get_uri (ctx);
-
- if (!server->valid_auths) {
- server->valid_auths = g_hash_table_new (g_str_hash,
- g_str_equal);
- }
- else if (g_hash_table_lookup_extended (server->valid_auths,
- uri->path,
- (gpointer *) &old_path,
- (gpointer *) &old_auth)) {
- if (auth == old_auth)
- return;
-
- g_hash_table_remove (server->valid_auths, old_path);
- g_free (old_path);
- soup_auth_free (old_auth);
- }
-
- g_hash_table_insert (server->valid_auths,
- g_strdup (uri->path),
- auth);
-}
-
typedef SoupAuth *(*SoupAuthNewFn) (void);
typedef struct {
static AuthScheme known_auth_schemes [] = {
{ "Basic", soup_auth_new_basic, 0 },
- { "NTLM", ntlm_new, 2 },
+ { "NTLM", soup_auth_new_ntlm, 2 },
{ "Digest", soup_auth_new_digest, 3 },
{ NULL }
};
auth->init_func (auth, uri);
}
+gboolean
+soup_auth_invalidate (SoupAuth *auth)
+{
+ g_return_val_if_fail (auth != NULL, FALSE);
+
+ return auth->invalidate_func (auth);
+}
+
gchar *
soup_auth_authorize (SoupAuth *auth, SoupMessage *msg)
{
g_free (auth->realm);
auth->free_func (auth);
}
+
+GSList *
+soup_auth_get_protection_space (SoupAuth *auth, const SoupUri *source_uri)
+{
+ g_return_val_if_fail (auth != NULL, NULL);
+ g_return_val_if_fail (source_uri != NULL, NULL);
+
+ return auth->pspace_func (auth, source_uri);
+}
+
+void
+soup_auth_free_protection_space (SoupAuth *auth, GSList *space)
+{
+ GSList *s;
+
+ for (s = space; s; s = s->next)
+ g_free (s->data);
+ g_slist_free (space);
+}