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(¶m, 0, sizeof(param));
+ while ((ret=http_parse_auth_param
+ (parser, ¶m.name, ¶m.value)) > 0) {
+ if (!array_is_created(params))
+ t_array_init(params, 4);
+ array_append(params, ¶m, 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