mirror of https://github.com/ipxe/ipxe.git
[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>pull/179/head
parent
c49acbb4d2
commit
96bd872c03
|
@ -150,14 +150,18 @@ struct http_request_content {
|
|||
size_t len;
|
||||
};
|
||||
|
||||
/** HTTP request authentication descriptor */
|
||||
struct http_request_auth {
|
||||
/** Authentication scheme (if any) */
|
||||
struct http_authentication *auth;
|
||||
/** HTTP request Basic authentication descriptor */
|
||||
struct http_request_auth_basic {
|
||||
/** Username */
|
||||
const char *username;
|
||||
/** Password */
|
||||
const char *password;
|
||||
};
|
||||
|
||||
/** HTTP request Digest authentication descriptor */
|
||||
struct http_request_auth_digest {
|
||||
/** Username */
|
||||
const char *username;
|
||||
/** Quality of protection */
|
||||
const char *qop;
|
||||
/** Algorithm */
|
||||
|
@ -168,6 +172,19 @@ struct http_request_auth {
|
|||
char response[ HTTP_DIGEST_RESPONSE_LEN + 1 /* NUL */ ];
|
||||
};
|
||||
|
||||
/** HTTP request authentication descriptor */
|
||||
struct http_request_auth {
|
||||
/** Authentication scheme (if any) */
|
||||
struct http_authentication *auth;
|
||||
/** Per-scheme information */
|
||||
union {
|
||||
/** Basic authentication descriptor */
|
||||
struct http_request_auth_basic basic;
|
||||
/** Digest authentication descriptor */
|
||||
struct http_request_auth_digest digest;
|
||||
};
|
||||
};
|
||||
|
||||
/** An HTTP request
|
||||
*
|
||||
* This represents a single request to be sent to a server, including
|
||||
|
@ -235,10 +252,12 @@ struct http_response_content {
|
|||
struct http_content_encoding *encoding;
|
||||
};
|
||||
|
||||
/** HTTP response authorization descriptor */
|
||||
struct http_response_auth {
|
||||
/** Authentication scheme (if any) */
|
||||
struct http_authentication *auth;
|
||||
/** HTTP response Basic authorization descriptor */
|
||||
struct http_response_auth_basic {
|
||||
};
|
||||
|
||||
/** HTTP response Digest authorization descriptor */
|
||||
struct http_response_auth_digest {
|
||||
/** Realm */
|
||||
const char *realm;
|
||||
/** Quality of protection */
|
||||
|
@ -251,6 +270,19 @@ struct http_response_auth {
|
|||
const char *opaque;
|
||||
};
|
||||
|
||||
/** HTTP response authorization descriptor */
|
||||
struct http_response_auth {
|
||||
/** Authentication scheme (if any) */
|
||||
struct http_authentication *auth;
|
||||
/** Per-scheme information */
|
||||
union {
|
||||
/** Basic authorization descriptor */
|
||||
struct http_response_auth_basic basic;
|
||||
/** Digest authorization descriptor */
|
||||
struct http_response_auth_digest digest;
|
||||
};
|
||||
};
|
||||
|
||||
/** An HTTP response
|
||||
*
|
||||
* This represents a single response received from the server,
|
||||
|
@ -461,6 +493,13 @@ struct http_content_encoding {
|
|||
struct http_authentication {
|
||||
/** Name (e.g. "Digest") */
|
||||
const char *name;
|
||||
/** Parse remaining "WWW-Authenticate" header line
|
||||
*
|
||||
* @v http HTTP transaction
|
||||
* @v line Remaining header line
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ( * parse ) ( struct http_transaction *http, char *line );
|
||||
/** Perform authentication
|
||||
*
|
||||
* @v http HTTP transaction
|
||||
|
|
|
@ -54,46 +54,6 @@ static struct http_authentication * http_authentication ( const char *name ) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/** An HTTP "WWW-Authenticate" response field */
|
||||
struct http_www_authenticate_field {
|
||||
/** Name */
|
||||
const char *name;
|
||||
/** Offset */
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
/** Define an HTTP "WWW-Authenticate" response field */
|
||||
#define HTTP_WWW_AUTHENTICATE_FIELD( _name ) { \
|
||||
.name = #_name, \
|
||||
.offset = offsetof ( struct http_transaction, \
|
||||
response.auth._name ), \
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP "WWW-Authenticate" response field value
|
||||
*
|
||||
* @v http HTTP transaction
|
||||
* @v field Response field
|
||||
* @v value Field value
|
||||
*/
|
||||
static inline void
|
||||
http_www_auth_field ( struct http_transaction *http,
|
||||
struct http_www_authenticate_field *field, char *value ) {
|
||||
char **ptr;
|
||||
|
||||
ptr = ( ( ( void * ) http ) + field->offset );
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
/** HTTP "WWW-Authenticate" fields */
|
||||
static struct http_www_authenticate_field http_www_auth_fields[] = {
|
||||
HTTP_WWW_AUTHENTICATE_FIELD ( realm ),
|
||||
HTTP_WWW_AUTHENTICATE_FIELD ( qop ),
|
||||
HTTP_WWW_AUTHENTICATE_FIELD ( algorithm ),
|
||||
HTTP_WWW_AUTHENTICATE_FIELD ( nonce ),
|
||||
HTTP_WWW_AUTHENTICATE_FIELD ( opaque ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse HTTP "WWW-Authenticate" header
|
||||
*
|
||||
|
@ -103,18 +63,15 @@ static struct http_www_authenticate_field http_www_auth_fields[] = {
|
|||
*/
|
||||
static int http_parse_www_authenticate ( struct http_transaction *http,
|
||||
char *line ) {
|
||||
struct http_www_authenticate_field *field;
|
||||
struct http_authentication *auth;
|
||||
char *name;
|
||||
char *key;
|
||||
char *value;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Get scheme name */
|
||||
name = http_token ( &line, NULL );
|
||||
if ( ! name ) {
|
||||
DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
|
||||
http, value );
|
||||
http, line );
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
|
@ -132,22 +89,13 @@ static int http_parse_www_authenticate ( struct http_transaction *http,
|
|||
return 0;
|
||||
http->response.auth.auth = auth;
|
||||
|
||||
/* Process fields */
|
||||
while ( ( key = http_token ( &line, &value ) ) ) {
|
||||
for ( i = 0 ; i < ( sizeof ( http_www_auth_fields ) /
|
||||
sizeof ( http_www_auth_fields[0] ) ) ; i++){
|
||||
field = &http_www_auth_fields[i];
|
||||
if ( strcasecmp ( key, field->name ) == 0 )
|
||||
http_www_auth_field ( http, field, value );
|
||||
}
|
||||
/* Parse remaining header line */
|
||||
if ( ( rc = auth->parse ( http, line ) ) != 0 ) {
|
||||
DBGC ( http, "HTTP %p could not parse %s WWW-Authenticate "
|
||||
"\"%s\": %s\n", http, name, line, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allow HTTP request to be retried if the request had not
|
||||
* already tried authentication.
|
||||
*/
|
||||
if ( ! http->request.auth.auth )
|
||||
http->response.flags |= HTTP_RESPONSE_RETRY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
__einfo_uniqify ( EINFO_EACCES, 0x01, \
|
||||
"No username available for Basic authentication" )
|
||||
|
||||
/**
|
||||
* Parse HTTP "WWW-Authenticate" header for Basic authentication
|
||||
*
|
||||
* @v http HTTP transaction
|
||||
* @v line Remaining header line
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_parse_basic_auth ( struct http_transaction *http,
|
||||
char *line __unused ) {
|
||||
|
||||
/* Allow HTTP request to be retried if the request had not
|
||||
* already tried authentication.
|
||||
*/
|
||||
if ( ! http->request.auth.auth )
|
||||
http->response.flags |= HTTP_RESPONSE_RETRY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform HTTP Basic authentication
|
||||
*
|
||||
|
@ -49,7 +68,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_basic_authenticate ( struct http_transaction *http ) {
|
||||
struct http_request_auth *req = &http->request.auth;
|
||||
struct http_request_auth_basic *req = &http->request.auth.basic;
|
||||
|
||||
/* Record username and password */
|
||||
if ( ! http->uri->user ) {
|
||||
|
@ -73,7 +92,7 @@ static int http_basic_authenticate ( struct http_transaction *http ) {
|
|||
*/
|
||||
static int http_format_basic_auth ( struct http_transaction *http,
|
||||
char *buf, size_t len ) {
|
||||
struct http_request_auth *req = &http->request.auth;
|
||||
struct http_request_auth_basic *req = &http->request.auth.basic;
|
||||
size_t user_pw_len = ( strlen ( req->username ) + 1 /* ":" */ +
|
||||
strlen ( req->password ) );
|
||||
char user_pw[ user_pw_len + 1 /* NUL */ ];
|
||||
|
@ -93,6 +112,7 @@ static int http_format_basic_auth ( struct http_transaction *http,
|
|||
/** HTTP Basic authentication scheme */
|
||||
struct http_authentication http_basic_auth __http_authentication = {
|
||||
.name = "Basic",
|
||||
.parse = http_parse_basic_auth,
|
||||
.authenticate = http_basic_authenticate,
|
||||
.format = http_format_basic_auth,
|
||||
};
|
||||
|
|
|
@ -45,6 +45,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
__einfo_uniqify ( EINFO_EACCES, 0x01, \
|
||||
"No username available for Digest authentication" )
|
||||
|
||||
/** An HTTP Digest "WWW-Authenticate" response field */
|
||||
struct http_digest_field {
|
||||
/** Name */
|
||||
const char *name;
|
||||
/** Offset */
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
/** Define an HTTP Digest "WWW-Authenticate" response field */
|
||||
#define HTTP_DIGEST_FIELD( _name ) { \
|
||||
.name = #_name, \
|
||||
.offset = offsetof ( struct http_transaction, \
|
||||
response.auth.digest._name ), \
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP Digest "WWW-Authenticate" response field value
|
||||
*
|
||||
* @v http HTTP transaction
|
||||
* @v field Response field
|
||||
* @v value Field value
|
||||
*/
|
||||
static inline void
|
||||
http_digest_field ( struct http_transaction *http,
|
||||
struct http_digest_field *field, char *value ) {
|
||||
char **ptr;
|
||||
|
||||
ptr = ( ( ( void * ) http ) + field->offset );
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
/** HTTP Digest "WWW-Authenticate" fields */
|
||||
static struct http_digest_field http_digest_fields[] = {
|
||||
HTTP_DIGEST_FIELD ( realm ),
|
||||
HTTP_DIGEST_FIELD ( qop ),
|
||||
HTTP_DIGEST_FIELD ( algorithm ),
|
||||
HTTP_DIGEST_FIELD ( nonce ),
|
||||
HTTP_DIGEST_FIELD ( opaque ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse HTTP "WWW-Authenticate" header for Digest authentication
|
||||
*
|
||||
* @v http HTTP transaction
|
||||
* @v line Remaining header line
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_parse_digest_auth ( struct http_transaction *http,
|
||||
char *line ) {
|
||||
struct http_digest_field *field;
|
||||
char *key;
|
||||
char *value;
|
||||
unsigned int i;
|
||||
|
||||
/* Process fields */
|
||||
while ( ( key = http_token ( &line, &value ) ) ) {
|
||||
for ( i = 0 ; i < ( sizeof ( http_digest_fields ) /
|
||||
sizeof ( http_digest_fields[0] ) ) ; i++){
|
||||
field = &http_digest_fields[i];
|
||||
if ( strcasecmp ( key, field->name ) == 0 )
|
||||
http_digest_field ( http, field, value );
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow HTTP request to be retried if the request had not
|
||||
* already tried authentication.
|
||||
*/
|
||||
if ( ! http->request.auth.auth )
|
||||
http->response.flags |= HTTP_RESPONSE_RETRY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise HTTP Digest
|
||||
*
|
||||
|
@ -95,13 +168,14 @@ static void http_digest_final ( struct md5_context *ctx, char *out,
|
|||
* @ret rc Return status code
|
||||
*/
|
||||
static int http_digest_authenticate ( struct http_transaction *http ) {
|
||||
struct http_request_auth *req = &http->request.auth;
|
||||
struct http_response_auth *rsp = &http->response.auth;
|
||||
struct http_request_auth_digest *req = &http->request.auth.digest;
|
||||
struct http_response_auth_digest *rsp = &http->response.auth.digest;
|
||||
char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
|
||||
char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
|
||||
static const char md5sess[] = "MD5-sess";
|
||||
static const char md5[] = "MD5";
|
||||
struct md5_context ctx;
|
||||
const char *password;
|
||||
|
||||
/* Check for required response parameters */
|
||||
if ( ! rsp->realm ) {
|
||||
|
@ -122,7 +196,7 @@ static int http_digest_authenticate ( struct http_transaction *http ) {
|
|||
return -EACCES_USERNAME;
|
||||
}
|
||||
req->username = http->uri->user;
|
||||
req->password = ( http->uri->password ? http->uri->password : "" );
|
||||
password = ( http->uri->password ? http->uri->password : "" );
|
||||
|
||||
/* Handle quality of protection */
|
||||
if ( rsp->qop ) {
|
||||
|
@ -146,7 +220,7 @@ static int http_digest_authenticate ( struct http_transaction *http ) {
|
|||
http_digest_init ( &ctx );
|
||||
http_digest_update ( &ctx, req->username );
|
||||
http_digest_update ( &ctx, rsp->realm );
|
||||
http_digest_update ( &ctx, req->password );
|
||||
http_digest_update ( &ctx, password );
|
||||
http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
|
||||
if ( req->algorithm == md5sess ) {
|
||||
http_digest_init ( &ctx );
|
||||
|
@ -187,8 +261,8 @@ static int http_digest_authenticate ( struct http_transaction *http ) {
|
|||
*/
|
||||
static int http_format_digest_auth ( struct http_transaction *http,
|
||||
char *buf, size_t len ) {
|
||||
struct http_request_auth *req = &http->request.auth;
|
||||
struct http_response_auth *rsp = &http->response.auth;
|
||||
struct http_request_auth_digest *req = &http->request.auth.digest;
|
||||
struct http_response_auth_digest *rsp = &http->response.auth.digest;
|
||||
size_t used = 0;
|
||||
|
||||
/* Sanity checks */
|
||||
|
@ -225,6 +299,7 @@ static int http_format_digest_auth ( struct http_transaction *http,
|
|||
/** HTTP Digest authentication scheme */
|
||||
struct http_authentication http_digest_auth __http_authentication = {
|
||||
.name = "Digest",
|
||||
.parse = http_parse_digest_auth,
|
||||
.authenticate = http_digest_authenticate,
|
||||
.format = http_format_digest_auth,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue