[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r12709 - in libmicrohttpd: . src/daemon src/examples src/in
From: |
gnunet |
Subject: |
[GNUnet-SVN] r12709 - in libmicrohttpd: . src/daemon src/examples src/include |
Date: |
Sun, 22 Aug 2010 16:49:49 +0200 |
Author: grothoff
Date: 2010-08-22 16:49:48 +0200 (Sun, 22 Aug 2010)
New Revision: 12709
Added:
libmicrohttpd/src/daemon/digestauth.c
libmicrohttpd/src/examples/digest_auth_example.c
Modified:
libmicrohttpd/AUTHORS
libmicrohttpd/ChangeLog
libmicrohttpd/configure.ac
libmicrohttpd/src/daemon/Makefile.am
libmicrohttpd/src/examples/Makefile.am
libmicrohttpd/src/include/microhttpd.h
Log:
initial draft for digest authentication (based on patch R3)
Modified: libmicrohttpd/AUTHORS
===================================================================
--- libmicrohttpd/AUTHORS 2010-08-22 13:36:42 UTC (rev 12708)
+++ libmicrohttpd/AUTHORS 2010-08-22 14:49:48 UTC (rev 12709)
@@ -3,6 +3,7 @@
Nils Durner <address@hidden> (W32 port)
Sagie Amir (TLS/SSL support using GNUtls)
Richard Alimi <address@hidden> (performance)
+Amr Ali <address@hidden> (digest authentication)
Code contributions also came from:
Chris GauthierDickey <address@hidden>
Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog 2010-08-22 13:36:42 UTC (rev 12708)
+++ libmicrohttpd/ChangeLog 2010-08-22 14:49:48 UTC (rev 12709)
@@ -1,3 +1,6 @@
+Sun Aug 22 16:49:13 CEST 2010
+ Initial draft for digest authentication. -AA
+
Thu Aug 19 14:15:01 CEST 2010
Changed code to enable error messages and HTTPS by default;
added option to disable post processor API (use
Modified: libmicrohttpd/configure.ac
===================================================================
--- libmicrohttpd/configure.ac 2010-08-22 13:36:42 UTC (rev 12708)
+++ libmicrohttpd/configure.ac 2010-08-22 14:49:48 UTC (rev 12709)
@@ -221,31 +221,37 @@
# optional: have error messages ?
AC_MSG_CHECKING(whether to enable error messages)
-AC_ARG_ENABLE(messages,
+AC_ARG_ENABLE([messages],
[AS_HELP_STRING([--disable-messages],
- [disable MHD error messages])],
- [disable_messages=$enableval],
+ [disable MHD error messages (default is NO)])],
+ [disable_messages="yes"],
[disable_messages="no"])
AC_MSG_RESULT($disable_messages)
if test "$disable_messages" = "no"
then
AC_DEFINE([HAVE_MESSAGES],[1],[Include error messages])
+ enable_messages="yes"
+else
+ AC_DEFINE([HAVE_MESSAGES],[0],[Disable error messages])
+ enable_messages="no"
fi
# optional: have postprocessor?
AC_MSG_CHECKING(whether to enable postprocessor)
-AC_ARG_ENABLE(postprocessor,
+AC_ARG_ENABLE([postprocessor],
[AS_HELP_STRING([--disable-postprocessor],
- [disable MHD PostProcessor functionality])],
- [disable_postprocessor=$enableval],
+ [disable MHD PostProcessor functionality (default is NO)])],
+ [disable_postprocessor="yes"],
[disable_postprocessor="no"])
AC_MSG_RESULT($disable_postprocessor)
if test "$disable_postprocessor" = "no"
then
- AC_DEFINE([HAVE_POSTPROCESSOR],[1],[Include postprocessor])
+ enable_postprocessor="yes"
+else
+ enable_postprocessor="no"
fi
-AM_CONDITIONAL([HAVE_POSTPROCESSOR],test x$disable_postprocessor = xno)
+AM_CONDITIONAL([HAVE_POSTPROCESSOR],test x$disable_postprocessor != xyes)
# optional: have zzuf, socat?
@@ -300,8 +306,8 @@
AC_MSG_CHECKING(whether to enable HTTPS support)
AC_ARG_ENABLE([https],
[AS_HELP_STRING([--disable-https],
- [disable HTTPS support (default is enabled)])],
- [disable_https=$enableval],
+ [disable HTTPS support (default is NO)])],
+ [disable_https="yes"],
[disable_https="no"])
if test "$disable_https" = "no"
then
@@ -309,17 +315,44 @@
then
AC_DEFINE([HTTPS_SUPPORT],[1],[include HTTPS support])
MHD_LIBDEPS="$LIBGCRYPT_LIBS"
+ enable_https="yes"
else
AC_DEFINE([HTTPS_SUPPORT],[0],[no libgcrypt or libgnutls])
enable_https="no (lacking libgcrypt or libgnutls)"
fi
else
AC_DEFINE([HTTPS_SUPPORT],[0],[disable HTTPS support])
+ enable_https="no (disabled)"
fi
AC_MSG_RESULT($disable_https)
AM_CONDITIONAL(ENABLE_HTTPS, test "$disable_https" = "no")
+# optional: HTTP Digest Auth support. Enabled by default
+AC_MSG_CHECKING(whether to disable HTTP Digest Auth support)
+AC_ARG_ENABLE([dauth],
+ AS_HELP_STRING([--disable-dauth],
+ [disable HTTP Digest Auth support (default is NO)]),
+ [disable_dauth="yes"],
+ [disable_dauth="no"])
+
+if test "x$disable_dauth" != "xyes"
+then
+ if test "$gcrypt" = "true"
+ then
+ enable_dauth="yes"
+ MHD_LIBDEPS="$LIBGCRYPT_LIBS"
+ else
+ disable_dauth="yes (lacking libgcrypt)"
+ enable_dauth="no (lacking libgcrypt)"
+ fi
+else
+ enable_dauth="no"
+fi
+AC_MSG_RESULT($disable_dauth)
+
+AM_CONDITIONAL(ENABLE_DAUTH, [test "x$disable_dauth" != "xyes" -a "$gcrypt" =
"true"])
+
MHD_LIB_LDFLAGS="-export-dynamic -no-undefined"
# TODO insert a proper check here
@@ -393,12 +426,13 @@
libgcrypt: ${MSG_GCRYPT}
libcurl (testing): ${MSG_CURL}
Target directory: ${prefix}
- Messages disabled: ${disable_messages}
- Postproc disabled: ${disable_postprocessor}
- HTTPS disabled: ${disable_https}
+ Messages: ${enable_messages}
+ HTTP Digest Auth: ${enable_dauth}
+ Postproc: ${enable_postprocessor}
+ HTTPS support: ${enable_https}
])
-if test "$disable_https" = "no"
+if test "x$enable_https" = "xyes"
then
AC_MSG_NOTICE([HTTPS subsystem configuration:
License : LGPL only
Modified: libmicrohttpd/src/daemon/Makefile.am
===================================================================
--- libmicrohttpd/src/daemon/Makefile.am 2010-08-22 13:36:42 UTC (rev
12708)
+++ libmicrohttpd/src/daemon/Makefile.am 2010-08-22 14:49:48 UTC (rev
12709)
@@ -13,9 +13,6 @@
lib_LTLIBRARIES = \
libmicrohttpd.la
-if HAVE_POSTPROCESSOR
- SUPPORT_POSTPROCESSOR = postprocessor.c
-endif
libmicrohttpd_la_SOURCES = \
connection.c connection.h \
@@ -23,7 +20,6 @@
daemon.c \
internal.c internal.h \
memorypool.c memorypool.h \
- $(SUPPORT_POSTPROCESSOR) \
response.c response.h
libmicrohttpd_la_LDFLAGS = \
$(MHD_LIB_LDFLAGS) \
@@ -33,7 +29,16 @@
AM_CFLAGS = --coverage
endif
+if HAVE_POSTPROCESSOR
+libmicrohttpd_la_SOURCES += \
+ postprocessor.c
+endif
+if ENABLE_DAUTH
+libmicrohttpd_la_SOURCES += \
+ digestauth.c
+endif
+
if ENABLE_HTTPS
libmicrohttpd_la_SOURCES += \
connection_https.c connection_https.h
Added: libmicrohttpd/src/daemon/digestauth.c
===================================================================
--- libmicrohttpd/src/daemon/digestauth.c (rev 0)
+++ libmicrohttpd/src/daemon/digestauth.c 2010-08-22 14:49:48 UTC (rev
12709)
@@ -0,0 +1,601 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2010 Daniel Pittman and Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
+*/
+
+/**
+ * @file digestauth.c
+ * @brief Implements HTTP/1.1 Digest Auth according to RFC2617
+ * @author Amr Ali
+ */
+
+#include <stdlib.h>
+#include <gcrypt.h>
+#include <string.h>
+#include <time.h>
+#include "internal.h"
+#include "connection.h"
+#include "microhttpd.h"
+
+#define HASH_MD5_LEN 16
+#define HASH_SHA1_LEN 20
+#define HASH_MD5_HEX_LEN 32
+#define HASH_SHA1_HEX_LEN 40
+
+#define _OPAQUE "opaque=\"11733b200778ce33060f31c9af70a870ba96ddd4\""
+#define _QOP "qop=\"auth\""
+#define _STALE "stale=true"
+#define _BASE "Digest "
+#define _REALM "realm="
+#define _NONCE "nonce="
+
+/* convert bin to hex */
+static void
+cvthex(const unsigned char *bin, size_t len, char *hex)
+{
+ size_t i;
+ unsigned int j;
+
+ for (i = 0; i < len; ++i) {
+ j = (bin[i] >> 4) & 0x0f;
+
+ hex[i * 2] = j <= 9 ? (j + '0') : (j + 'a' - 10);
+
+ j = bin[i] & 0x0f;
+
+ hex[i * 2 + 1] = j <= 9 ? (j + '0') : (j + 'a' - 10);
+ }
+
+ hex[len * 2] = '\0';
+}
+
+/* calculate H(A1) as per RFC2617 spec */
+static int
+digest_calc_ha1(const char *alg,
+ const char *username,
+ const char *realm,
+ const char *password,
+ const char *nonce,
+ const char *cnonce,
+ char *sessionkey)
+{
+ gcry_md_hd_t md5;
+ gcry_error_t gerror;
+ unsigned char *ha1;
+
+ gerror = gcry_md_open(&md5, GCRY_MD_MD5, GCRY_MD_FLAG_SECURE);
+
+ if (gerror) return gerror;
+
+ gcry_md_write(md5, username, strlen(username));
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, realm, strlen(realm));
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, password, strlen(password));
+ gcry_md_final(md5);
+
+ ha1 = gcry_md_read(md5, GCRY_MD_MD5);
+
+ if (strcasecmp(alg, "md5-sess") == 0) {
+ gcry_md_reset(md5);
+ gcry_md_write(md5, ha1, HASH_MD5_LEN);
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, nonce, strlen(nonce));
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, cnonce, strlen(cnonce));
+ gcry_md_final(md5);
+
+ ha1 = gcry_md_read(md5, GCRY_MD_MD5);
+ }
+
+ cvthex(ha1, HASH_MD5_LEN, sessionkey);
+ gcry_md_close(md5);
+
+ return 0;
+}
+
+/* calculate request-digest/response-digest as per RFC2617 spec */
+static int
+digest_calc_response(const char *ha1, /* H(A1) */
+ const char *nonce, /* nonce from server */
+ const char *noncecount, /* 8 hex digits */
+ const char *cnonce, /* client nonce
*/
+ const char *qop, /* qop-value: "",
"auth", "auth-int" */
+ const char *method, /* method from
the request */
+ const char *uri, /* requested URL */
+ const char *hentity, /* H(entity body) if
qop="auth-int" */
+ char *response /*
request-digest or response-digest */
+ )
+{
+ gcry_md_hd_t md5;
+ gcry_error_t gerror;
+ unsigned char *ha2;
+ unsigned char *resphash;
+ char ha2hex[HASH_MD5_HEX_LEN + 1];
+
+ gerror = gcry_md_open(&md5, GCRY_MD_MD5, GCRY_MD_FLAG_SECURE);
+
+ if (gerror) return gerror;
+
+ /*
+ * calculate H(A2)
+ */
+
+ gcry_md_write(md5, method, strlen(method));
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, uri, strlen(uri));
+
+ if (strcasecmp(qop, "auth-int") == 0) {
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, hentity, strlen(hentity));
+ }
+
+ gcry_md_final(md5);
+
+ ha2 = gcry_md_read(md5, GCRY_MD_MD5);
+
+ cvthex(ha2, HASH_MD5_LEN, ha2hex);
+ gcry_md_reset(md5);
+
+ /*
+ * calculate response
+ */
+
+ gcry_md_write(md5, ha1, HASH_MD5_HEX_LEN);
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, nonce, strlen(nonce));
+ gcry_md_write(md5, ":", 1);
+
+ if (*qop) {
+ gcry_md_write(md5, noncecount, strlen(noncecount));
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, cnonce, strlen(cnonce));
+ gcry_md_write(md5, ":", 1);
+ gcry_md_write(md5, qop, strlen(qop));
+ gcry_md_write(md5, ":", 1);
+ }
+
+ gcry_md_write(md5, ha2hex, HASH_MD5_HEX_LEN);
+ gcry_md_final(md5);
+
+ resphash = gcry_md_read(md5, GCRY_MD_MD5);
+
+ cvthex(resphash, HASH_MD5_LEN, response);
+ gcry_md_close(md5);
+
+ return 0;
+}
+
+static const char *
+lookup_sub_value(char *data, size_t len, const char *key)
+{
+ char *tmp = data;
+ char *value = NULL;
+ size_t keylen;
+ size_t i;
+
+ keylen = strlen(key);
+
+ for (i = 0; i < len; ++i) {
+ if (strncmp(tmp, key, keylen) == 0 &&
+ strncmp(tmp + keylen, "=", 1) == 0) {
+ tmp += keylen;
+ break;
+ } else {
+ tmp++;
+ }
+
+ if ((i + 1) == len) return NULL;
+ }
+
+ while (1) {
+ tmp++;
+
+ if (*tmp == '"' && *(tmp + 1) == ',') {
+ *tmp = '\0';
+ break;
+ }
+
+ if (*tmp == '"' && *(tmp + 1) == '\0') {
+ *tmp = '\0';
+ break;
+ }
+
+ if (*tmp == ',' || *tmp == '\0') {
+ *tmp = '\0';
+ break;
+ }
+
+ if (*tmp == '"') continue;
+
+ if (value == NULL)
+ value = tmp;
+ }
+
+ return value;
+}
+
+
+/**
+ * Get the username from the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no username could be found, a pointer
+ * to the username if found
+ */
+char *
+MHD_digest_auth_get_username(struct MHD_Connection *connection)
+{
+ size_t len;
+ size_t userlen;
+ char *buffer;
+ char *username;
+ const char *user;
+ const char *header;
+
+ header = MHD_lookup_connection_value(connection,
+ MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
+
+ if (header == NULL) return NULL;
+ if (strncmp(header, _BASE, strlen(_BASE)) != 0) return NULL;
+
+ len = strlen(header) - strlen(_BASE) + 1;
+ buffer = malloc(len);
+
+ if (buffer == NULL) return NULL;
+
+ strncpy(buffer, header + strlen(_BASE), len);
+
+ user = lookup_sub_value(buffer, len, "username");
+
+ if (user) {
+ userlen = strlen(user) + 1;
+ username = malloc(userlen);
+
+ if (username != NULL) {
+ strncpy(username, user, userlen);
+ free(buffer);
+ return username;
+ }
+ }
+
+ free(buffer);
+ return NULL;
+}
+
+/**
+ * Authenticates the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm The realm presented to the client
+ * @param username The username needs to be authenticated
+ * @param password The password used in the authentication
+ * @param nonce_timeout The amount of time for a nonce to be
+ * invalid in seconds
+ * @return MHD_YES if authenticated, MHD_NO if not,
+ * MHD_INVALID_NONCE if nonce is invalid
+ */
+int
+MHD_digest_auth_check(struct MHD_Connection *connection,
+ const char *realm,
+ const char *username,
+ const char *password,
+ unsigned int nonce_timeout)
+{
+ int auth;
+ size_t len;
+ char *buffer;
+ const char *header;
+ const char *ret;
+ const char *nonce;
+ const char *cnonce;
+ const char *uri;
+ const char *qop;
+ const char *nc;
+ const char *response;
+ unsigned char *tmpnonce;
+ char *hentity = NULL; /* "auth-int" is not supported */
+ char timestamp[5];
+ char ha1[HASH_MD5_HEX_LEN + 1];
+ char respexp[HASH_MD5_HEX_LEN + 1];
+ char noncehashexp[HASH_SHA1_HEX_LEN + 9];
+ unsigned int nonce_time;
+ time_t t;
+ gcry_error_t gerror;
+ gcry_md_hd_t sha1;
+
+ header = MHD_lookup_connection_value(
+ connection, MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_AUTHORIZATION);
+
+ if (header == NULL) return MHD_NO;
+ if (strncmp(header, _BASE, strlen(_BASE)) != 0) return MHD_NO;
+
+ len = strlen(header) - strlen(_BASE) + 1;
+
+ buffer = malloc(len);
+
+ if (buffer == NULL) return MHD_NO;
+
+ strncpy(buffer, header + strlen(_BASE), len);
+
+ ret = lookup_sub_value(buffer, len, "username");
+
+ if (ret == NULL || strcmp(username, ret) != 0) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ ret = lookup_sub_value(buffer, len, "realm");
+
+ if (ret == NULL || strcmp(realm, ret) != 0) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ if ((uri = lookup_sub_value(buffer, len, "uri")) == NULL) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ if ((nonce = lookup_sub_value(buffer, len, "nonce")) == NULL) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ /*
+ * 8 = 4 hexadecimal numbers for the timestamp
+ */
+
+ nonce_time = strtoul(nonce + strlen(nonce) - 8, 0, 16);
+
+ time(&t);
+
+ /*
+ * First level vetting for the nonce validity
+ * if the timestamp attached to the nonce
+ * exceeds `nonce_timeout' then the nonce is
+ * invalid.
+ */
+
+ if (t - nonce_time > nonce_timeout) {
+ free(buffer);
+ return MHD_INVALID_NONCE;
+ }
+
+ gerror = gcry_md_open(&sha1, GCRY_MD_SHA1, GCRY_MD_FLAG_SECURE);
+
+ if (gerror) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ timestamp[0] = (nonce_time & 0xff000000) >> 0x18;
+ timestamp[1] = (nonce_time & 0x00ff0000) >> 0x10;
+ timestamp[2] = (nonce_time & 0x0000ff00) >> 0x08;
+ timestamp[3] = nonce_time & 0x000000ff;
+ timestamp[4] = '\0';
+
+ gcry_md_write(sha1, timestamp, 4);
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, connection->method, strlen(connection->method));
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, password, strlen(password));
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, uri, strlen(uri));
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, realm, strlen(realm));
+ gcry_md_final(sha1);
+
+ tmpnonce = gcry_md_read(sha1, GCRY_MD_SHA1);
+
+ cvthex(tmpnonce, HASH_SHA1_LEN, noncehashexp);
+ gcry_md_close(sha1);
+
+ strncat(noncehashexp, nonce + strlen(nonce) - 8, 8);
+
+ /*
+ * Second level vetting for the nonce validity
+ * if the timestamp attached to the nonce is valid
+ * and possibility fabricated (in case of an attack)
+ * the attacker must also know the password to be
+ * able to generate a "sane" nonce, which if he does
+ * not, the nonce fabrication process going to be
+ * very hard to achieve.
+ */
+
+ if (strncmp(nonce, noncehashexp, strlen(nonce)) != 0) {
+ free(buffer);
+ return MHD_INVALID_NONCE;
+ }
+
+ if ((cnonce = lookup_sub_value(buffer, len, "cnonce")) == NULL) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ if ((qop = lookup_sub_value(buffer, len, "qop")) == NULL) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ if ((nc = lookup_sub_value(buffer, len, "nc")) == NULL) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ if ((response = lookup_sub_value(buffer, len, "response")) == NULL) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ auth = digest_calc_ha1(
+ "md5",
+ username,
+ realm,
+ password,
+ nonce,
+ cnonce,
+ ha1
+ );
+
+ if (auth) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ auth = digest_calc_response(
+ ha1,
+ nonce,
+ nc,
+ cnonce,
+ qop,
+ connection->method,
+ uri,
+ hentity,
+ respexp
+ );
+
+ if (auth) {
+ free(buffer);
+ return MHD_NO;
+ }
+
+ auth = strcmp(response, respexp) == 0 ? MHD_YES : MHD_NO;
+
+ free(buffer);
+
+ return auth;
+}
+
+/**
+ * Queues a response to request authentication from the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm The realm presented to the client
+ * @param password The password used in authentication
+ * @param signal_stale MHD_YES if the nonce is invalid to add
+ * 'stale=true' to the authentication header
+ * @return MHD_YES on success, MHD_NO otherwise
+ */
+int
+MHD_queue_auth_fail_response(struct MHD_Connection *connection,
+ const char *realm,
+ const char *password,
+ const char *opaque,
+ int signal_stale)
+{
+ int ret;
+ size_t hlen;
+ unsigned char *tmpnonce;
+ char *header;
+ unsigned char timestamp[5];
+ char timestamphex[9];
+ char nonce[HASH_SHA1_HEX_LEN + 9];
+ time_t t;
+ struct MHD_Response *response;
+ gcry_error_t gerror;
+ gcry_md_hd_t sha1;
+
+ response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);
+
+ if (!response) return MHD_NO;
+
+ /*
+ * Generating the server nonce
+ */
+
+ gerror = gcry_md_open(&sha1, GCRY_MD_SHA1, GCRY_MD_FLAG_SECURE);
+
+ if (gerror) return MHD_NO;
+
+ time(&t);
+
+ timestamp[0] = (t & 0xff000000) >> 0x18;
+ timestamp[1] = (t & 0x00ff0000) >> 0x10;
+ timestamp[2] = (t & 0x0000ff00) >> 0x08;
+ timestamp[3] = t & 0x000000ff;
+ timestamp[4] = '\0';
+
+ gcry_md_write(sha1, timestamp, 4);
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, connection->method, strlen(connection->method));
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, password, strlen(password));
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, connection->url, strlen(connection->url));
+ gcry_md_write(sha1, ":", 1);
+ gcry_md_write(sha1, realm, strlen(realm));
+ gcry_md_final(sha1);
+
+ tmpnonce = gcry_md_read(sha1, GCRY_MD_SHA1);
+
+ cvthex(timestamp, 4, timestamphex);
+ cvthex(tmpnonce, HASH_SHA1_LEN, nonce);
+ strncat(nonce, timestamphex, 8);
+ gcry_md_close(sha1);
+
+ /*
+ * Building the authentication header
+ */
+
+ /* 4(single quotes) + 3(commas) + NULL = 8 */
+ hlen = strlen(_BASE) + strlen(_REALM) + strlen(realm) +
+ strlen(_QOP) + strlen(_NONCE) + strlen(nonce) +
+ strlen(_OPAQUE) + 8;
+
+ /* 1(comma for stale=true) */
+ if (signal_stale)
+ hlen += strlen(_STALE) + 1;
+
+ header = malloc(hlen);
+
+ if (header == NULL) return MHD_NO;
+
+ snprintf(header, hlen,
+ "%s%s\"%s\",%s,%s\"%s\",%s",
+ _BASE, _REALM, realm, _QOP,
+ _NONCE, nonce, _OPAQUE);
+
+ /* Add "stale=true" to the authentication header if nonce is invalid */
+ if (signal_stale) {
+ strncat(header, ",", 1);
+ strncat(header, _STALE, strlen(_STALE));
+ }
+
+ /*
+ * Sending response with authentication header
+ */
+
+ ret = MHD_add_response_header(response,
+ MHD_HTTP_HEADER_WWW_AUTHENTICATE, header);
+
+ free(header);
+
+ if(!ret) {
+ MHD_destroy_response(response);
+ return MHD_NO;
+ }
+
+ ret = MHD_queue_response(connection, MHD_HTTP_UNAUTHORIZED, response);
+
+ MHD_destroy_response(response);
+
+ return ret;
+}
+
+/* end of digestauth.c */
Modified: libmicrohttpd/src/examples/Makefile.am
===================================================================
--- libmicrohttpd/src/examples/Makefile.am 2010-08-22 13:36:42 UTC (rev
12708)
+++ libmicrohttpd/src/examples/Makefile.am 2010-08-22 14:49:48 UTC (rev
12709)
@@ -28,6 +28,10 @@
noinst_PROGRAMS += https_fileserver_example
endif
+if ENABLE_DAUTH
+noinst_PROGRAMS += digest_auth_example
+endif
+
minimal_example_SOURCES = \
minimal_example.c
minimal_example_LDADD = \
@@ -43,6 +47,11 @@
authorization_example_LDADD = \
$(top_builddir)/src/daemon/libmicrohttpd.la
+digest_auth_example_SOURCES = \
+ digest_auth_example.c
+digest_auth_example_LDADD = \
+ $(top_builddir)/src/daemon/libmicrohttpd.la
+
refuse_post_example_SOURCES = \
refuse_post_example.c
refuse_post_example_LDADD = \
Added: libmicrohttpd/src/examples/digest_auth_example.c
===================================================================
--- libmicrohttpd/src/examples/digest_auth_example.c
(rev 0)
+++ libmicrohttpd/src/examples/digest_auth_example.c 2010-08-22 14:49:48 UTC
(rev 12709)
@@ -0,0 +1,105 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2010 Christian Grothoff (and other contributing authors)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
+*/
+/**
+ * @file digest_auth_example.c
+ * @brief minimal example for how to use digest auth with libmicrohttpd
+ * @author Amr Ali
+ */
+
+#include "platform.h"
+#include <microhttpd.h>
+#include <stdlib.h>
+
+#define PAGE "<html><head><title>libmicrohttpd
demo</title></head><body>libmicrohttpd demo</body></html>"
+
+#define OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
+
+static int
+ahc_echo (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data, size_t *upload_data_size, void **ptr)
+{
+ struct MHD_Response *response;
+ char *username;
+ const char *password = "testpass";
+ const char *realm = "address@hidden";
+ int ret;
+
+ username = MHD_digest_auth_get_username(connection);
+
+ if (username == NULL) {
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ password,
+ OPAQUE,
+ MHD_NO);
+
+ return ret;
+ }
+
+ ret = MHD_digest_auth_check(connection, realm,
+ username, password, 300);
+
+ free(username);
+
+ if (ret == MHD_INVALID_NONCE) {
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ password,
+ OPAQUE, MHD_YES);
+
+ return ret;
+ }
+
+ if (ret == MHD_NO) {
+ ret = MHD_queue_auth_fail_response(connection, realm,
+ password, OPAQUE, MHD_NO);
+
+ return ret;
+ }
+
+ response = MHD_create_response_from_data(strlen(PAGE), PAGE,
+ MHD_NO, MHD_NO);
+
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+
+ MHD_destroy_response(response);
+ return ret;
+}
+
+int
+main (int argc, char *const *argv)
+{
+ struct MHD_Daemon *d;
+
+ if (argc != 2)
+ {
+ printf ("%s PORT\n", argv[0]);
+ return 1;
+ }
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ atoi (argv[1]),
+ NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ (void) getc (stdin);
+ MHD_stop_daemon (d);
+ return 0;
+}
Modified: libmicrohttpd/src/include/microhttpd.h
===================================================================
--- libmicrohttpd/src/include/microhttpd.h 2010-08-22 13:36:42 UTC (rev
12708)
+++ libmicrohttpd/src/include/microhttpd.h 2010-08-22 14:49:48 UTC (rev
12709)
@@ -94,6 +94,11 @@
#define MHD_NO 0
/**
+ * MHD digest auth internal code for an invalid nonce.
+ */
+#define MHD_INVALID_NONCE -1
+
+/**
* Constant used to indicate unknown size (use when
* creating a response).
*/
@@ -1215,7 +1220,66 @@
int MHD_destroy_post_processor (struct MHD_PostProcessor *pp);
+/* ********************* Digest Authentication functions *************** */
+
+/**
+ * Constant to indicate that the nonce of the provided
+ * authentication code was wrong.
+ */
+#define MHD_INVALID_NONCE -1
+
+
+/**
+ * Get the username from the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no username could be found, a pointer
+ * to the username if found
+ */
+char *
+MHD_digest_auth_get_username(struct MHD_Connection *connection);
+
+
+/**
+ * Authenticates the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm The realm presented to the client
+ * @param username The username needs to be authenticated
+ * @param password The password used in the authentication
+ * @param nonce_timeout The amount of time for a nonce to be
+ * invalid in seconds
+ * @return MHD_YES if authenticated, MHD_NO if not,
+ * MHD_INVALID_NONCE if nonce is invalid
+ */
+int
+MHD_digest_auth_check(struct MHD_Connection *connection,
+ const char *realm,
+ const char *username,
+ const char *password,
+ unsigned int nonce_timeout);
+
+
+/**
+ * Queues a response to request authentication from the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm The realm presented to the client
+ * @param password The password used in authentication
+ * @param opaque string to user for opaque value
+ * @param signal_stale MHD_YES if the nonce is invalid to add
+ * 'stale=true' to the authentication header
+ * @return MHD_YES on success, MHD_NO otherwise
+ */
+int
+MHD_queue_auth_fail_response(struct MHD_Connection *connection,
+ const char *realm,
+ const char *password,
+ const char *opaque,
+ int signal_stale);
+
+
/* ********************** generic query functions ********************** */
/**
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r12709 - in libmicrohttpd: . src/daemon src/examples src/include,
gnunet <=