Browse Source

[http] Handle parsing of WWW-Authenticate header within authentication scheme

Allow individual authentication schemes to parse WWW-Authenticate
headers that do not comply with RFC2617.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 6 years ago
parent
commit
96bd872c03
4 changed files with 157 additions and 75 deletions
  1. 47
    8
      src/include/ipxe/http.h
  2. 7
    59
      src/net/tcp/httpauth.c
  3. 22
    2
      src/net/tcp/httpbasic.c
  4. 81
    6
      src/net/tcp/httpdigest.c

+ 47
- 8
src/include/ipxe/http.h View File

@@ -150,14 +150,18 @@ struct http_request_content {
150 150
 	size_t len;
151 151
 };
152 152
 
153
-/** HTTP request authentication descriptor */
154
-struct http_request_auth {
155
-	/** Authentication scheme (if any) */
156
-	struct http_authentication *auth;
153
+/** HTTP request Basic authentication descriptor */
154
+struct http_request_auth_basic {
157 155
 	/** Username */
158 156
 	const char *username;
159 157
 	/** Password */
160 158
 	const char *password;
159
+};
160
+
161
+/** HTTP request Digest authentication descriptor */
162
+struct http_request_auth_digest {
163
+	/** Username */
164
+	const char *username;
161 165
 	/** Quality of protection */
162 166
 	const char *qop;
163 167
 	/** Algorithm */
@@ -168,6 +172,19 @@ struct http_request_auth {
168 172
 	char response[ HTTP_DIGEST_RESPONSE_LEN + 1 /* NUL */ ];
169 173
 };
170 174
 
175
+/** HTTP request authentication descriptor */
176
+struct http_request_auth {
177
+	/** Authentication scheme (if any) */
178
+	struct http_authentication *auth;
179
+	/** Per-scheme information */
180
+	union {
181
+		/** Basic authentication descriptor */
182
+		struct http_request_auth_basic basic;
183
+		/** Digest authentication descriptor */
184
+		struct http_request_auth_digest digest;
185
+	};
186
+};
187
+
171 188
 /** An HTTP request
172 189
  *
173 190
  * This represents a single request to be sent to a server, including
@@ -235,10 +252,12 @@ struct http_response_content {
235 252
 	struct http_content_encoding *encoding;
236 253
 };
237 254
 
238
-/** HTTP response authorization descriptor */
239
-struct http_response_auth {
240
-	/** Authentication scheme (if any) */
241
-	struct http_authentication *auth;
255
+/** HTTP response Basic authorization descriptor */
256
+struct http_response_auth_basic {
257
+};
258
+
259
+/** HTTP response Digest authorization descriptor */
260
+struct http_response_auth_digest {
242 261
 	/** Realm */
243 262
 	const char *realm;
244 263
 	/** Quality of protection */
@@ -251,6 +270,19 @@ struct http_response_auth {
251 270
 	const char *opaque;
252 271
 };
253 272
 
273
+/** HTTP response authorization descriptor */
274
+struct http_response_auth {
275
+	/** Authentication scheme (if any) */
276
+	struct http_authentication *auth;
277
+	/** Per-scheme information */
278
+	union {
279
+		/** Basic authorization descriptor */
280
+		struct http_response_auth_basic basic;
281
+		/** Digest authorization descriptor */
282
+		struct http_response_auth_digest digest;
283
+	};
284
+};
285
+
254 286
 /** An HTTP response
255 287
  *
256 288
  * This represents a single response received from the server,
@@ -461,6 +493,13 @@ struct http_content_encoding {
461 493
 struct http_authentication {
462 494
 	/** Name (e.g. "Digest") */
463 495
 	const char *name;
496
+	/** Parse remaining "WWW-Authenticate" header line
497
+	 *
498
+	 * @v http		HTTP transaction
499
+	 * @v line		Remaining header line
500
+	 * @ret rc		Return status code
501
+	 */
502
+	int ( * parse ) ( struct http_transaction *http, char *line );
464 503
 	/** Perform authentication
465 504
 	 *
466 505
 	 * @v http		HTTP transaction

+ 7
- 59
src/net/tcp/httpauth.c View File

@@ -54,46 +54,6 @@ static struct http_authentication * http_authentication ( const char *name ) {
54 54
 	return NULL;
55 55
 }
56 56
 
57
-/** An HTTP "WWW-Authenticate" response field */
58
-struct http_www_authenticate_field {
59
-	/** Name */
60
-	const char *name;
61
-	/** Offset */
62
-	size_t offset;
63
-};
64
-
65
-/** Define an HTTP "WWW-Authenticate" response field */
66
-#define HTTP_WWW_AUTHENTICATE_FIELD( _name ) {				\
67
-		.name = #_name,						\
68
-		.offset = offsetof ( struct http_transaction,		\
69
-				     response.auth._name ),		\
70
-	}
71
-
72
-/**
73
- * Set HTTP "WWW-Authenticate" response field value
74
- *
75
- * @v http		HTTP transaction
76
- * @v field		Response field
77
- * @v value		Field value
78
- */
79
-static inline void
80
-http_www_auth_field ( struct http_transaction *http,
81
-		      struct http_www_authenticate_field *field, char *value ) {
82
-	char **ptr;
83
-
84
-	ptr = ( ( ( void * ) http ) + field->offset );
85
-	*ptr = value;
86
-}
87
-
88
-/** HTTP "WWW-Authenticate" fields */
89
-static struct http_www_authenticate_field http_www_auth_fields[] = {
90
-	HTTP_WWW_AUTHENTICATE_FIELD ( realm ),
91
-	HTTP_WWW_AUTHENTICATE_FIELD ( qop ),
92
-	HTTP_WWW_AUTHENTICATE_FIELD ( algorithm ),
93
-	HTTP_WWW_AUTHENTICATE_FIELD ( nonce ),
94
-	HTTP_WWW_AUTHENTICATE_FIELD ( opaque ),
95
-};
96
-
97 57
 /**
98 58
  * Parse HTTP "WWW-Authenticate" header
99 59
  *
@@ -103,18 +63,15 @@ static struct http_www_authenticate_field http_www_auth_fields[] = {
103 63
  */
104 64
 static int http_parse_www_authenticate ( struct http_transaction *http,
105 65
 					 char *line ) {
106
-	struct http_www_authenticate_field *field;
107 66
 	struct http_authentication *auth;
108 67
 	char *name;
109
-	char *key;
110
-	char *value;
111
-	unsigned int i;
68
+	int rc;
112 69
 
113 70
 	/* Get scheme name */
114 71
 	name = http_token ( &line, NULL );
115 72
 	if ( ! name ) {
116 73
 		DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
117
-		       http, value );
74
+		       http, line );
118 75
 		return -EPROTO;
119 76
 	}
120 77
 
@@ -132,22 +89,13 @@ static int http_parse_www_authenticate ( struct http_transaction *http,
132 89
 		return 0;
133 90
 	http->response.auth.auth = auth;
134 91
 
135
-	/* Process fields */
136
-	while ( ( key = http_token ( &line, &value ) ) ) {
137
-		for ( i = 0 ; i < ( sizeof ( http_www_auth_fields ) /
138
-				    sizeof ( http_www_auth_fields[0] ) ) ; i++){
139
-			field = &http_www_auth_fields[i];
140
-			if ( strcasecmp ( key, field->name ) == 0 )
141
-				http_www_auth_field ( http, field, value );
142
-		}
92
+	/* Parse remaining header line */
93
+	if ( ( rc = auth->parse ( http, line ) ) != 0 ) {
94
+		DBGC ( http, "HTTP %p could not parse %s WWW-Authenticate "
95
+		       "\"%s\": %s\n", http, name, line, strerror ( rc ) );
96
+		return rc;
143 97
 	}
144 98
 
145
-	/* Allow HTTP request to be retried if the request had not
146
-	 * already tried authentication.
147
-	 */
148
-	if ( ! http->request.auth.auth )
149
-		http->response.flags |= HTTP_RESPONSE_RETRY;
150
-
151 99
 	return 0;
152 100
 }
153 101
 

+ 22
- 2
src/net/tcp/httpbasic.c View File

@@ -42,6 +42,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
42 42
 	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
43 43
 			  "No username available for Basic authentication" )
44 44
 
45
+/**
46
+ * Parse HTTP "WWW-Authenticate" header for Basic authentication
47
+ *
48
+ * @v http		HTTP transaction
49
+ * @v line		Remaining header line
50
+ * @ret rc		Return status code
51
+ */
52
+static int http_parse_basic_auth ( struct http_transaction *http,
53
+				   char *line __unused ) {
54
+
55
+	/* Allow HTTP request to be retried if the request had not
56
+	 * already tried authentication.
57
+	 */
58
+	if ( ! http->request.auth.auth )
59
+		http->response.flags |= HTTP_RESPONSE_RETRY;
60
+
61
+	return 0;
62
+}
63
+
45 64
 /**
46 65
  * Perform HTTP Basic authentication
47 66
  *
@@ -49,7 +68,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
49 68
  * @ret rc		Return status code
50 69
  */
51 70
 static int http_basic_authenticate ( struct http_transaction *http ) {
52
-	struct http_request_auth *req = &http->request.auth;
71
+	struct http_request_auth_basic *req = &http->request.auth.basic;
53 72
 
54 73
 	/* Record username and password */
55 74
 	if ( ! http->uri->user ) {
@@ -73,7 +92,7 @@ static int http_basic_authenticate ( struct http_transaction *http ) {
73 92
  */
74 93
 static int http_format_basic_auth ( struct http_transaction *http,
75 94
 				    char *buf, size_t len ) {
76
-	struct http_request_auth *req = &http->request.auth;
95
+	struct http_request_auth_basic *req = &http->request.auth.basic;
77 96
 	size_t user_pw_len = ( strlen ( req->username ) + 1 /* ":" */ +
78 97
 			       strlen ( req->password ) );
79 98
 	char user_pw[ user_pw_len + 1 /* NUL */ ];
@@ -93,6 +112,7 @@ static int http_format_basic_auth ( struct http_transaction *http,
93 112
 /** HTTP Basic authentication scheme */
94 113
 struct http_authentication http_basic_auth __http_authentication = {
95 114
 	.name = "Basic",
115
+	.parse = http_parse_basic_auth,
96 116
 	.authenticate = http_basic_authenticate,
97 117
 	.format = http_format_basic_auth,
98 118
 };

+ 81
- 6
src/net/tcp/httpdigest.c View File

@@ -45,6 +45,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
45 45
 	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
46 46
 			  "No username available for Digest authentication" )
47 47
 
48
+/** An HTTP Digest "WWW-Authenticate" response field */
49
+struct http_digest_field {
50
+	/** Name */
51
+	const char *name;
52
+	/** Offset */
53
+	size_t offset;
54
+};
55
+
56
+/** Define an HTTP Digest "WWW-Authenticate" response field */
57
+#define HTTP_DIGEST_FIELD( _name ) {					\
58
+		.name = #_name,						\
59
+		.offset = offsetof ( struct http_transaction,		\
60
+				     response.auth.digest._name ),	\
61
+	}
62
+
63
+/**
64
+ * Set HTTP Digest "WWW-Authenticate" response field value
65
+ *
66
+ * @v http		HTTP transaction
67
+ * @v field		Response field
68
+ * @v value		Field value
69
+ */
70
+static inline void
71
+http_digest_field ( struct http_transaction *http,
72
+		    struct http_digest_field *field, char *value ) {
73
+	char **ptr;
74
+
75
+	ptr = ( ( ( void * ) http ) + field->offset );
76
+	*ptr = value;
77
+}
78
+
79
+/** HTTP Digest "WWW-Authenticate" fields */
80
+static struct http_digest_field http_digest_fields[] = {
81
+	HTTP_DIGEST_FIELD ( realm ),
82
+	HTTP_DIGEST_FIELD ( qop ),
83
+	HTTP_DIGEST_FIELD ( algorithm ),
84
+	HTTP_DIGEST_FIELD ( nonce ),
85
+	HTTP_DIGEST_FIELD ( opaque ),
86
+};
87
+
88
+/**
89
+ * Parse HTTP "WWW-Authenticate" header for Digest authentication
90
+ *
91
+ * @v http		HTTP transaction
92
+ * @v line		Remaining header line
93
+ * @ret rc		Return status code
94
+ */
95
+static int http_parse_digest_auth ( struct http_transaction *http,
96
+				    char *line ) {
97
+	struct http_digest_field *field;
98
+	char *key;
99
+	char *value;
100
+	unsigned int i;
101
+
102
+	/* Process fields */
103
+	while ( ( key = http_token ( &line, &value ) ) ) {
104
+		for ( i = 0 ; i < ( sizeof ( http_digest_fields ) /
105
+				    sizeof ( http_digest_fields[0] ) ) ; i++){
106
+			field = &http_digest_fields[i];
107
+			if ( strcasecmp ( key, field->name ) == 0 )
108
+				http_digest_field ( http, field, value );
109
+		}
110
+	}
111
+
112
+	/* Allow HTTP request to be retried if the request had not
113
+	 * already tried authentication.
114
+	 */
115
+	if ( ! http->request.auth.auth )
116
+		http->response.flags |= HTTP_RESPONSE_RETRY;
117
+
118
+	return 0;
119
+}
120
+
48 121
 /**
49 122
  * Initialise HTTP Digest
50 123
  *
@@ -95,13 +168,14 @@ static void http_digest_final ( struct md5_context *ctx, char *out,
95 168
  * @ret rc		Return status code
96 169
  */
97 170
 static int http_digest_authenticate ( struct http_transaction *http ) {
98
-	struct http_request_auth *req = &http->request.auth;
99
-	struct http_response_auth *rsp = &http->response.auth;
171
+	struct http_request_auth_digest *req = &http->request.auth.digest;
172
+	struct http_response_auth_digest *rsp = &http->response.auth.digest;
100 173
 	char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
101 174
 	char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
102 175
 	static const char md5sess[] = "MD5-sess";
103 176
 	static const char md5[] = "MD5";
104 177
 	struct md5_context ctx;
178
+	const char *password;
105 179
 
106 180
 	/* Check for required response parameters */
107 181
 	if ( ! rsp->realm ) {
@@ -122,7 +196,7 @@ static int http_digest_authenticate ( struct http_transaction *http ) {
122 196
 		return -EACCES_USERNAME;
123 197
 	}
124 198
 	req->username = http->uri->user;
125
-	req->password = ( http->uri->password ? http->uri->password : "" );
199
+	password = ( http->uri->password ? http->uri->password : "" );
126 200
 
127 201
 	/* Handle quality of protection */
128 202
 	if ( rsp->qop ) {
@@ -146,7 +220,7 @@ static int http_digest_authenticate ( struct http_transaction *http ) {
146 220
 	http_digest_init ( &ctx );
147 221
 	http_digest_update ( &ctx, req->username );
148 222
 	http_digest_update ( &ctx, rsp->realm );
149
-	http_digest_update ( &ctx, req->password );
223
+	http_digest_update ( &ctx, password );
150 224
 	http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
151 225
 	if ( req->algorithm == md5sess ) {
152 226
 		http_digest_init ( &ctx );
@@ -187,8 +261,8 @@ static int http_digest_authenticate ( struct http_transaction *http ) {
187 261
  */
188 262
 static int http_format_digest_auth ( struct http_transaction *http,
189 263
 				     char *buf, size_t len ) {
190
-	struct http_request_auth *req = &http->request.auth;
191
-	struct http_response_auth *rsp = &http->response.auth;
264
+	struct http_request_auth_digest *req = &http->request.auth.digest;
265
+	struct http_response_auth_digest *rsp = &http->response.auth.digest;
192 266
 	size_t used = 0;
193 267
 
194 268
 	/* Sanity checks */
@@ -225,6 +299,7 @@ static int http_format_digest_auth ( struct http_transaction *http,
225 299
 /** HTTP Digest authentication scheme */
226 300
 struct http_authentication http_digest_auth __http_authentication = {
227 301
 	.name = "Digest",
302
+	.parse = http_parse_digest_auth,
228 303
 	.authenticate = http_digest_authenticate,
229 304
 	.format = http_format_digest_auth,
230 305
 };

Loading…
Cancel
Save