dovecot-2.2: lib-http: Implemented HTTP auth (RFC 7235).

dovecot at dovecot.org dovecot at dovecot.org
Wed Sep 10 10:44:54 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/2121057f994b
changeset: 17771:2121057f994b
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Wed Sep 10 13:39:37 2014 +0300
description:
lib-http: Implemented HTTP auth (RFC 7235).

diffstat:

 src/lib-http/Makefile.am      |   10 +
 src/lib-http/http-auth.c      |  427 ++++++++++++++++++++++++++++++++++++++++++
 src/lib-http/http-auth.h      |   70 ++++++
 src/lib-http/http-parser.c    |   73 ++++---
 src/lib-http/http-parser.h    |    6 +
 src/lib-http/test-http-auth.c |  274 ++++++++++++++++++++++++++
 6 files changed, 829 insertions(+), 31 deletions(-)

diffs (truncated from 963 to 300 lines):

diff -r b7c29e47b0f6 -r 2121057f994b src/lib-http/Makefile.am
--- a/src/lib-http/Makefile.am	Wed Sep 10 13:39:37 2014 +0300
+++ b/src/lib-http/Makefile.am	Wed Sep 10 13:39:37 2014 +0300
@@ -14,6 +14,7 @@
 	http-header.c \
 	http-header-parser.c \
 	http-transfer-chunked.c \
+	http-auth.c \
 	http-message-parser.c \
 	http-request.c \
 	http-request-parser.c \
@@ -37,6 +38,7 @@
 	http-header.h \
 	http-header-parser.h \
 	http-transfer.h \
+	http-auth.h \
 	http-message-parser.h \
 	http-request.h \
 	http-request-parser.h \
@@ -55,6 +57,7 @@
 	test-http-url \
 	test-http-header-parser \
 	test-http-transfer \
+	test-http-auth \
 	test-http-response-parser \
 	test-http-request-parser
 
@@ -95,6 +98,13 @@
 	$(test_libs)
 test_http_transfer_DEPENDENCIES = $(test_deps)
 
+test_http_auth_SOURCES = test-http-auth.c
+test_http_auth_LDADD = \
+	http-auth.lo \
+	http-parser.lo \
+	$(test_libs)
+test_http_auth_DEPENDENCIES = $(test_deps)
+
 test_http_response_parser_SOURCES = test-http-response-parser.c
 test_http_response_parser_LDADD = \
 	http-date.lo \
diff -r b7c29e47b0f6 -r 2121057f994b src/lib-http/http-auth.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-http/http-auth.c	Wed Sep 10 13:39:37 2014 +0300
@@ -0,0 +1,427 @@
+/* Copyright (c) 2013-2014 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+#include "http-parser.h"
+
+#include "http-auth.h"
+
+/* RFC 7235, Section 2.1:
+
+   challenge      = auth-scheme [ 1*SP ( token68 / #auth-param ) ]
+   credentials    = auth-scheme [ 1*SP ( token68 / #auth-param ) ]
+
+   auth-scheme    = token
+   auth-param     = token BWS "=" BWS ( token / quoted-string )
+   token68        = 1*( ALPHA / DIGIT /
+                      "-" / "." / "_" / "~" / "+" / "/" ) *"="
+
+   OWS            = *( SP / HTAB )
+                  ; optional whitespace
+   BWS            = OWS
+                  ; "bad" whitespace
+ */
+
+/*
+ * Parsing
+ */
+
+static int
+http_parse_token68(struct http_parser *parser, const char **token68_r)
+{
+	const unsigned char *first;
+
+	/* token68        = 1*( ALPHA / DIGIT /
+                      "-" / "." / "_" / "~" / "+" / "/" ) *"="
+	 */
+
+	/* 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) */
+	if (parser->cur >= parser->end || !http_char_is_token68(*parser->cur))
+		return 0;
+	first = parser->cur++;
+	while (parser->cur < parser->end && http_char_is_token68(*parser->cur))
+		parser->cur++;
+
+	/* *"=" */
+	while (parser->cur < parser->end && *parser->cur == '=')
+		parser->cur++;
+	
+	*token68_r = t_strndup(first, parser->cur - first);
+	return 1;
+}
+
+static int
+http_parse_auth_param(struct http_parser *parser,
+	const char **param_r, const char **value_r)
+{
+	const unsigned char *first = parser->cur, *end_token;
+	int ret;
+
+	/* auth-param     = token BWS "=" BWS ( token / quoted-string ) */
+
+	/* token */
+	if ((ret=http_parser_skip_token(parser)) <= 0) {
+		parser->cur = first;
+		return ret;
+	}
+	end_token = parser->cur;
+
+	/* BWS "=" BWS */
+	http_parse_ows(parser);
+	if (parser->cur >= parser->end || *parser->cur != '=') {
+		parser->cur = first;
+		return 0;
+	}
+	parser->cur++;
+	http_parse_ows(parser);
+
+	/* ( token / quoted-string ) */
+	if ((ret=http_parse_token_or_qstring(parser, value_r)) <= 0) {
+		parser->cur = first;
+		return ret;
+	}
+
+	*param_r = t_strndup(first, end_token - first);
+	return 1;
+}
+
+static int
+http_parse_auth_params(struct http_parser *parser,
+	ARRAY_TYPE(http_auth_param) *params)
+{
+	const unsigned char *last = parser->cur;
+	struct http_auth_param param;
+	unsigned int count = 0;
+	int ret;
+
+	memset(&param, 0, sizeof(param));
+	while ((ret=http_parse_auth_param
+		(parser, &param.name, &param.value)) > 0) {
+		if (!array_is_created(params))
+			t_array_init(params, 4);
+		array_append(params, &param, 1);
+		count++;
+
+		last = parser->cur;
+
+		/* OWS "," OWS 
+		   --> also allow empty elements
+		 */
+		for (;;) {
+			http_parse_ows(parser);
+			if (parser->cur >= parser->end || *parser->cur != ',')
+				break;
+			parser->cur++;
+		}
+	}
+	
+	parser->cur = last;
+	if (ret < 0)
+		return -1;
+	return (count > 0 ? 1 : 0);
+}
+
+int http_auth_parse_challenges(const unsigned char *data, size_t size,
+	ARRAY_TYPE(http_auth_challenge) *chlngs)
+{
+	struct http_parser parser;
+	int ret;
+
+	http_parser_init(&parser, data, size);
+
+	/* WWW-Authenticate   = 1#challenge
+	   Proxy-Authenticate = 1#challenge
+
+	   challenge      = auth-scheme [ 1*SP ( token68 / #auth-param ) ]
+	   auth-scheme    = token
+	 */
+
+	/* 1#element => *( "," OWS ) ... ; RFC 7230, Section 7 */
+	for (;;) {
+		if (parser.cur >= parser.end || *parser.cur != ',')
+			break;
+		parser.cur++;
+		http_parse_ows(&parser);
+	}
+
+	for (;;) {
+		struct http_auth_challenge chlng;
+
+		memset(&chlng, 0, sizeof(chlng));
+
+		/* auth-scheme */
+		if ((ret=http_parse_token(&parser, &chlng.scheme)) <= 0) {
+			if (ret < 0)
+				return -1;
+			break;
+		}
+
+		/* [ 1*SP ... ] */
+		if (parser.cur >= parser.end || *parser.cur != ' ')
+			return 1;
+		parser.cur++;
+		while (parser.cur < parser.end && *parser.cur == ' ')
+			parser.cur++;
+
+		/* ( token68 / #auth-param ) */
+		if ((ret=http_parse_auth_params(&parser, &chlng.params)) <= 0) {
+			if (ret < 0)
+				return -1;
+			if (http_parse_token68(&parser, &chlng.data) < 0)
+				return -1;
+		}
+
+		if (!array_is_created(chlngs))
+			t_array_init(chlngs, 4);
+		array_append(chlngs, &chlng, 1);
+
+		/* OWS "," OWS 
+		   --> also allow empty elements
+		 */
+		for (;;) {
+			http_parse_ows(&parser);
+			if (parser.cur >= parser.end || *parser.cur != ',')
+				break;
+			parser.cur++;
+		}
+	}
+
+	if (parser.cur != parser.end)
+		return -1;
+	return 1;
+}
+
+int http_auth_parse_credentials(const unsigned char *data, size_t size,
+	struct http_auth_credentials *crdts)
+{
+	struct http_parser parser;
+	int ret;
+
+	http_parser_init(&parser, data, size);
+
+	/* Authorization       = credentials
+	   Proxy-Authorization = credentials
+
+	   credentials    = auth-scheme [ 1*SP ( token68 / #auth-param ) ]
+	   auth-scheme    = token
+	 */
+
+	memset(crdts, 0, sizeof(*crdts));
+
+	/* auth-scheme */
+	if (http_parse_token(&parser, &crdts->scheme) <= 0)
+		return -1;
+
+	/* [ 1*SP ... ] */
+	if (parser.cur >= parser.end || *parser.cur != ' ')
+		return 1;
+	parser.cur++;
+	while (parser.cur < parser.end && *parser.cur == ' ')
+		parser.cur++;
+
+	/* ( token68 / #auth-param ) */
+	if ((ret=http_parse_auth_params(&parser, &crdts->params)) <= 0) {
+		if (ret < 0)
+			return -1;
+		if (http_parse_token68(&parser, &crdts->data) < 0)
+			return -1;
+	}
+
+	if (parser.cur != parser.end)
+		return -1;
+	return 1;
+}
+
+/*
+ * Construction
+ */
+
+static void
+http_auth_create_param(string_t *out, const struct http_auth_param *param)
+{
+	const char *p, *first;
+
+	/* auth-param     = token BWS "=" BWS ( token / quoted-string ) */
+
+	str_append(out, param->name);
+	str_append_c(out, '=');
+
+	for (p = param->value; *p != '\0' && http_char_is_token(*p); p++);
+
+	if ( *p != '\0' ) {
+		str_append_c(out, '"');
+		p = first = param->value;
+		while (*p != '\0') {


More information about the dovecot-cvs mailing list