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
 	size_t len;
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
 	/** Username */
155
 	/** Username */
158
 	const char *username;
156
 	const char *username;
159
 	/** Password */
157
 	/** Password */
160
 	const char *password;
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
 	/** Quality of protection */
165
 	/** Quality of protection */
162
 	const char *qop;
166
 	const char *qop;
163
 	/** Algorithm */
167
 	/** Algorithm */
168
 	char response[ HTTP_DIGEST_RESPONSE_LEN + 1 /* NUL */ ];
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
 /** An HTTP request
188
 /** An HTTP request
172
  *
189
  *
173
  * This represents a single request to be sent to a server, including
190
  * This represents a single request to be sent to a server, including
235
 	struct http_content_encoding *encoding;
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
 	/** Realm */
261
 	/** Realm */
243
 	const char *realm;
262
 	const char *realm;
244
 	/** Quality of protection */
263
 	/** Quality of protection */
251
 	const char *opaque;
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
 /** An HTTP response
286
 /** An HTTP response
255
  *
287
  *
256
  * This represents a single response received from the server,
288
  * This represents a single response received from the server,
461
 struct http_authentication {
493
 struct http_authentication {
462
 	/** Name (e.g. "Digest") */
494
 	/** Name (e.g. "Digest") */
463
 	const char *name;
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
 	/** Perform authentication
503
 	/** Perform authentication
465
 	 *
504
 	 *
466
 	 * @v http		HTTP transaction
505
 	 * @v http		HTTP transaction

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

54
 	return NULL;
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
  * Parse HTTP "WWW-Authenticate" header
58
  * Parse HTTP "WWW-Authenticate" header
99
  *
59
  *
103
  */
63
  */
104
 static int http_parse_www_authenticate ( struct http_transaction *http,
64
 static int http_parse_www_authenticate ( struct http_transaction *http,
105
 					 char *line ) {
65
 					 char *line ) {
106
-	struct http_www_authenticate_field *field;
107
 	struct http_authentication *auth;
66
 	struct http_authentication *auth;
108
 	char *name;
67
 	char *name;
109
-	char *key;
110
-	char *value;
111
-	unsigned int i;
68
+	int rc;
112
 
69
 
113
 	/* Get scheme name */
70
 	/* Get scheme name */
114
 	name = http_token ( &line, NULL );
71
 	name = http_token ( &line, NULL );
115
 	if ( ! name ) {
72
 	if ( ! name ) {
116
 		DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
73
 		DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
117
-		       http, value );
74
+		       http, line );
118
 		return -EPROTO;
75
 		return -EPROTO;
119
 	}
76
 	}
120
 
77
 
132
 		return 0;
89
 		return 0;
133
 	http->response.auth.auth = auth;
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
 	return 0;
99
 	return 0;
152
 }
100
 }
153
 
101
 

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

42
 	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
42
 	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
43
 			  "No username available for Basic authentication" )
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
  * Perform HTTP Basic authentication
65
  * Perform HTTP Basic authentication
47
  *
66
  *
49
  * @ret rc		Return status code
68
  * @ret rc		Return status code
50
  */
69
  */
51
 static int http_basic_authenticate ( struct http_transaction *http ) {
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
 	/* Record username and password */
73
 	/* Record username and password */
55
 	if ( ! http->uri->user ) {
74
 	if ( ! http->uri->user ) {
73
  */
92
  */
74
 static int http_format_basic_auth ( struct http_transaction *http,
93
 static int http_format_basic_auth ( struct http_transaction *http,
75
 				    char *buf, size_t len ) {
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
 	size_t user_pw_len = ( strlen ( req->username ) + 1 /* ":" */ +
96
 	size_t user_pw_len = ( strlen ( req->username ) + 1 /* ":" */ +
78
 			       strlen ( req->password ) );
97
 			       strlen ( req->password ) );
79
 	char user_pw[ user_pw_len + 1 /* NUL */ ];
98
 	char user_pw[ user_pw_len + 1 /* NUL */ ];
93
 /** HTTP Basic authentication scheme */
112
 /** HTTP Basic authentication scheme */
94
 struct http_authentication http_basic_auth __http_authentication = {
113
 struct http_authentication http_basic_auth __http_authentication = {
95
 	.name = "Basic",
114
 	.name = "Basic",
115
+	.parse = http_parse_basic_auth,
96
 	.authenticate = http_basic_authenticate,
116
 	.authenticate = http_basic_authenticate,
97
 	.format = http_format_basic_auth,
117
 	.format = http_format_basic_auth,
98
 };
118
 };

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

45
 	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
45
 	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
46
 			  "No username available for Digest authentication" )
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
  * Initialise HTTP Digest
122
  * Initialise HTTP Digest
50
  *
123
  *
95
  * @ret rc		Return status code
168
  * @ret rc		Return status code
96
  */
169
  */
97
 static int http_digest_authenticate ( struct http_transaction *http ) {
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
 	char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
173
 	char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
101
 	char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
174
 	char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
102
 	static const char md5sess[] = "MD5-sess";
175
 	static const char md5sess[] = "MD5-sess";
103
 	static const char md5[] = "MD5";
176
 	static const char md5[] = "MD5";
104
 	struct md5_context ctx;
177
 	struct md5_context ctx;
178
+	const char *password;
105
 
179
 
106
 	/* Check for required response parameters */
180
 	/* Check for required response parameters */
107
 	if ( ! rsp->realm ) {
181
 	if ( ! rsp->realm ) {
122
 		return -EACCES_USERNAME;
196
 		return -EACCES_USERNAME;
123
 	}
197
 	}
124
 	req->username = http->uri->user;
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
 	/* Handle quality of protection */
201
 	/* Handle quality of protection */
128
 	if ( rsp->qop ) {
202
 	if ( rsp->qop ) {
146
 	http_digest_init ( &ctx );
220
 	http_digest_init ( &ctx );
147
 	http_digest_update ( &ctx, req->username );
221
 	http_digest_update ( &ctx, req->username );
148
 	http_digest_update ( &ctx, rsp->realm );
222
 	http_digest_update ( &ctx, rsp->realm );
149
-	http_digest_update ( &ctx, req->password );
223
+	http_digest_update ( &ctx, password );
150
 	http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
224
 	http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
151
 	if ( req->algorithm == md5sess ) {
225
 	if ( req->algorithm == md5sess ) {
152
 		http_digest_init ( &ctx );
226
 		http_digest_init ( &ctx );
187
  */
261
  */
188
 static int http_format_digest_auth ( struct http_transaction *http,
262
 static int http_format_digest_auth ( struct http_transaction *http,
189
 				     char *buf, size_t len ) {
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
 	size_t used = 0;
266
 	size_t used = 0;
193
 
267
 
194
 	/* Sanity checks */
268
 	/* Sanity checks */
225
 /** HTTP Digest authentication scheme */
299
 /** HTTP Digest authentication scheme */
226
 struct http_authentication http_digest_auth __http_authentication = {
300
 struct http_authentication http_digest_auth __http_authentication = {
227
 	.name = "Digest",
301
 	.name = "Digest",
302
+	.parse = http_parse_digest_auth,
228
 	.authenticate = http_digest_authenticate,
303
 	.authenticate = http_digest_authenticate,
229
 	.format = http_format_digest_auth,
304
 	.format = http_format_digest_auth,
230
 };
305
 };

Loading…
Cancel
Save