dmitry Tue Jan 25 06:03:20 2005 EDT Modified files: /php-src/ext/soap php_http.c Log: Fixed bug #28041 (SOAP HTTP Digest Access Authentication was implemented)
http://cvs.php.net/diff.php/php-src/ext/soap/php_http.c?r1=1.63&r2=1.64&ty=u Index: php-src/ext/soap/php_http.c diff -u php-src/ext/soap/php_http.c:1.63 php-src/ext/soap/php_http.c:1.64 --- php-src/ext/soap/php_http.c:1.63 Thu Jan 20 12:29:16 2005 +++ php-src/ext/soap/php_http.c Tue Jan 25 06:03:20 2005 @@ -17,10 +17,11 @@ | Dmitry Stogov <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ -/* $Id: php_http.c,v 1.63 2005/01/20 17:29:16 dmitry Exp $ */ +/* $Id: php_http.c,v 1.64 2005/01/25 11:03:20 dmitry Exp $ */ #include "php_soap.h" #include "ext/standard/base64.h" +#include "ext/standard/md5.h" static char *get_http_header_value(char *headers, char *type); static int get_http_body(php_stream *socketd, int close, char *headers, char **response, int *out_size TSRMLS_DC); @@ -126,7 +127,7 @@ STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL /*persistent_id*/, NULL /*timeout*/, - context, + context, NULL, NULL); efree(name); #else @@ -199,13 +200,13 @@ } } -int make_http_soap_request(zval *this_ptr, +int make_http_soap_request(zval *this_ptr, char *buf, int buf_size, - char *location, - char *soapaction, + char *location, + char *soapaction, int soap_version, - char **buffer, + char **buffer, int *buffer_len TSRMLS_DC) { char *request; @@ -286,7 +287,7 @@ phpurl = php_url_parse(location); } -try_again: +try_again: if (phpurl == NULL || phpurl->host == NULL) { if (phpurl != NULL) {php_url_free(phpurl);} if (request != buf) {efree(request);} @@ -427,23 +428,164 @@ smart_str_append_const(&soap_headers, "\r\n"); /* HTTP Authentication */ - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS) { - char* buf; - int len; - - smart_str auth = {0}; - smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login)); - smart_str_appendc(&auth, ':'); - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS) { - smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password)); - } - smart_str_0(&auth); - buf = php_base64_encode(auth.c, auth.len, &len); - smart_str_append_const(&soap_headers, "Authorization: Basic "); - smart_str_appendl(&soap_headers, buf, len); - smart_str_append_const(&soap_headers, "\r\n"); - efree(buf); - smart_str_free(&auth); + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS && + Z_TYPE_PP(login) == IS_STRING) { + zval **digest; + + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == SUCCESS) { + if (Z_TYPE_PP(digest) == IS_ARRAY) { + char HA1[33], HA2[33], response[33], cnonce[33], nc[9]; + PHP_MD5_CTX md5ctx; + unsigned char hash[16]; + + PHP_MD5Init(&md5ctx); + sprintf(cnonce, "%d", rand()); + PHP_MD5Update(&md5ctx, cnonce, strlen(cnonce)); + PHP_MD5Final(hash, &md5ctx); + make_digest(cnonce, hash); + + if (zend_hash_find(Z_ARRVAL_PP(digest), "nc", sizeof("nc"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_LONG) { + Z_LVAL_PP(tmp)++; + sprintf(nc, "%08ld", Z_LVAL_PP(tmp)); + } else { + add_assoc_long(*digest, "nc", 1); + strcpy(nc, "00000001"); + } + + PHP_MD5Init(&md5ctx); + PHP_MD5Update(&md5ctx, Z_STRVAL_PP(login), Z_STRLEN_PP(login)); + PHP_MD5Update(&md5ctx, ":", 1); + if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + PHP_MD5Update(&md5ctx, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + PHP_MD5Update(&md5ctx, ":", 1); + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS && + Z_TYPE_PP(password) == IS_STRING) { + PHP_MD5Update(&md5ctx, Z_STRVAL_PP(password), Z_STRLEN_PP(password)); + } + PHP_MD5Final(hash, &md5ctx); + make_digest(HA1, hash); + if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING && + Z_STRLEN_PP(tmp) == sizeof("md5-sess")-1 && + stricmp(Z_STRVAL_PP(tmp), "md5-sess") == 0) { + PHP_MD5Init(&md5ctx); + PHP_MD5Update(&md5ctx, HA1, 32); + PHP_MD5Update(&md5ctx, ":", 1); + if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + PHP_MD5Update(&md5ctx, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + PHP_MD5Update(&md5ctx, ":", 1); + PHP_MD5Update(&md5ctx, cnonce, 8); + PHP_MD5Final(hash, &md5ctx); + make_digest(HA1, hash); + } + + PHP_MD5Init(&md5ctx); + PHP_MD5Update(&md5ctx, "POST:", sizeof("POST:")-1); + if (phpurl->path) { + PHP_MD5Update(&md5ctx, phpurl->path, strlen(phpurl->path)); + } + if (phpurl->query) { + PHP_MD5Update(&md5ctx, "?", 1); + PHP_MD5Update(&md5ctx, phpurl->query, strlen(phpurl->query)); + } + + /* TODO: Support for qop="auth-int" */ +/* + if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING && + Z_STRLEN_PP(tmp) == sizeof("auth-int")-1 && + stricmp(Z_STRVAL_PP(tmp), "auth-int") == 0) { + PHP_MD5Update(&md5ctx, ":", 1); + PHP_MD5Update(&md5ctx, HEntity, HASHHEXLEN); + } +*/ + PHP_MD5Final(hash, &md5ctx); + make_digest(HA2, hash); + + PHP_MD5Init(&md5ctx); + PHP_MD5Update(&md5ctx, HA1, 32); + PHP_MD5Update(&md5ctx, ":", 1); + if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + PHP_MD5Update(&md5ctx, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + PHP_MD5Update(&md5ctx, ":", 1); + if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + PHP_MD5Update(&md5ctx, nc, 8); + PHP_MD5Update(&md5ctx, ":", 1); + PHP_MD5Update(&md5ctx, cnonce, 8); + PHP_MD5Update(&md5ctx, ":", 1); + /* TODO: Support for qop="auth-int" */ + PHP_MD5Update(&md5ctx, "auth", sizeof("auth")-1); + PHP_MD5Update(&md5ctx, ":", 1); + } + PHP_MD5Update(&md5ctx, HA2, 32); + PHP_MD5Final(hash, &md5ctx); + make_digest(response, hash); + + smart_str_append_const(&soap_headers, "Authorization: Digest username=\""); + smart_str_appendl(&soap_headers, Z_STRVAL_PP(login), Z_STRLEN_PP(login)); + if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + smart_str_append_const(&soap_headers, "\", realm=\""); + smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + smart_str_append_const(&soap_headers, "\", nonce=\""); + smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + smart_str_append_const(&soap_headers, "\", uri=\""); + if (phpurl->path) { + smart_str_appends(&soap_headers, phpurl->path); + } + if (phpurl->query) { + smart_str_appendc(&soap_headers, '?'); + smart_str_appends(&soap_headers, phpurl->query); + } + if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + /* TODO: Support for qop="auth-int" */ + smart_str_append_const(&soap_headers, "\", qop=\"auth"); + smart_str_append_const(&soap_headers, "\", nc=\""); + smart_str_appendl(&soap_headers, nc, 8); + smart_str_append_const(&soap_headers, "\", cnonce=\""); + smart_str_appendl(&soap_headers, cnonce, 8); + } + smart_str_append_const(&soap_headers, "\", response=\""); + smart_str_appendl(&soap_headers, response, 32); + if (zend_hash_find(Z_ARRVAL_PP(digest), "opaque", sizeof("opaque"), (void **)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + smart_str_append_const(&soap_headers, "\", opaque=\""); + smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + smart_str_append_const(&soap_headers, "\"\r\n"); + } + } else { + char* buf; + int len; + + smart_str auth = {0}; + smart_str_appendl(&auth, Z_STRVAL_PP(login), Z_STRLEN_PP(login)); + smart_str_appendc(&auth, ':'); + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS && + Z_TYPE_PP(password) == IS_STRING) { + smart_str_appendl(&auth, Z_STRVAL_PP(password), Z_STRLEN_PP(password)); + } + smart_str_0(&auth); + buf = php_base64_encode(auth.c, auth.len, &len); + smart_str_append_const(&soap_headers, "Authorization: Basic "); + smart_str_appendl(&soap_headers, buf, len); + smart_str_append_const(&soap_headers, "\r\n"); + efree(buf); + smart_str_free(&auth); + } } /* Proxy HTTP Authentication */ @@ -544,48 +686,6 @@ } efree(http_version); - /* Process HTTP status codes */ - if (http_status >= 200 && http_status < 300) { - } else if (http_status >= 300 && http_status < 400) { - char *loc; - - if ((loc = get_http_header_value(http_headers,"Location: ")) != NULL) { - php_url *new_url = php_url_parse(loc); - char *body; - int body_size; - - if (new_url != NULL) { - if (get_http_body(stream, !http_1_1, http_headers, &body, &body_size TSRMLS_CC)) { - efree(body); - } else { - php_stream_close(stream); - zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); - stream = NULL; - } - efree(http_headers); - efree(loc); - if (new_url->scheme == NULL && new_url->path != NULL) { - new_url->scheme = estrdup(phpurl->scheme); - new_url->host = estrdup(phpurl->host); - new_url->port = phpurl->port; - if (new_url->path && new_url->path[0] != '/') { - char *t = phpurl->path?phpurl->path:"/"; - char *p = strrchr(t, '/'); - char *s = emalloc((p - t) + strlen(new_url->path) + 2); - - strncpy(s, t, (p - t) + 1); - s[(p - t) + 1] = 0; - strcat(s, new_url->path); - efree(new_url->path); - new_url->path = s; - } - } - phpurl = new_url; - goto try_again; - } - } - } - /* Try and get headers again */ if (http_status == 100) { efree(http_headers); @@ -725,6 +825,127 @@ zend_hash_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")); } + /* Process HTTP status codes */ + if (http_status >= 300 && http_status < 400) { + char *loc; + + if ((loc = get_http_header_value(http_headers,"Location: ")) != NULL) { + php_url *new_url = php_url_parse(loc); + char *body; + int body_size; + + if (new_url != NULL) { + if (get_http_body(stream, !http_1_1, http_headers, &body, &body_size TSRMLS_CC)) { + efree(body); + } else { + php_stream_close(stream); + zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")); + stream = NULL; + } + efree(http_headers); + efree(http_body); + efree(loc); + if (new_url->scheme == NULL && new_url->path != NULL) { + new_url->scheme = estrdup(phpurl->scheme); + new_url->host = estrdup(phpurl->host); + new_url->port = phpurl->port; + if (new_url->path && new_url->path[0] != '/') { + char *t = phpurl->path?phpurl->path:"/"; + char *p = strrchr(t, '/'); + char *s = emalloc((p - t) + strlen(new_url->path) + 2); + + strncpy(s, t, (p - t) + 1); + s[(p - t) + 1] = 0; + strcat(s, new_url->path); + efree(new_url->path); + new_url->path = s; + } + } + phpurl = new_url; + + goto try_again; + } + } + } else if (http_status == 401) { + /* Digest authentication */ + zval **digest, **login, **password; + char *auth = get_http_header_value(http_headers, "WWW-Authenticate: "); + + if (auth && + strstr(auth, "Digest") == auth && + (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == FAILURE || + Z_TYPE_PP(digest) != IS_ARRAY) && + zend_hash_find(Z_OBJPROP_P(this_ptr), "_login", sizeof("_login"), (void **)&login) == SUCCESS && + Z_TYPE_PP(login) == IS_STRING && + zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS && + Z_TYPE_PP(password) == IS_STRING) { + char *s; + zval *digest = NULL; + + s = auth + sizeof("Digest")-1; + while (*s != '\0') { + char *name, *val; + while (*s == ' ') ++s; + name = s; + while (*s != '\0' && *s != '=') ++s; + if (*s == '=') { + *s = '\0'; + ++s; + if (*s == '"') { + ++s; + val = s; + while (*s != '\0' && *s != '"') ++s; + } else { + val = s; + while (*s != '\0' && *s != ' ' && *s != ',') ++s; + } + if (*s != '\0') { + if (*s != ',') { + *s = '\0'; + ++s; + while (*s != '\0' && *s != ',') ++s; + if (*s != '\0') ++s; + } else { + *s = '\0'; + ++s; + } + } + if (digest == NULL) { + ALLOC_INIT_ZVAL(digest); + array_init(digest); + } + add_assoc_string(digest, name, val ,1); + } + } + + if (digest != NULL) { + php_url *new_url = emalloc(sizeof(php_url)); + +#ifdef ZEND_ENGINE_2 + digest->refcount--; +#endif + add_property_zval_ex(this_ptr, "_digest", sizeof("_digest"), digest TSRMLS_CC); + + *new_url = *phpurl; + if (phpurl->scheme) phpurl->scheme = estrdup(phpurl->scheme); + if (phpurl->user) phpurl->user = estrdup(phpurl->user); + if (phpurl->pass) phpurl->pass = estrdup(phpurl->pass); + if (phpurl->host) phpurl->host = estrdup(phpurl->host); + if (phpurl->path) phpurl->path = estrdup(phpurl->path); + if (phpurl->query) phpurl->query = estrdup(phpurl->query); + if (phpurl->fragment) phpurl->fragment = estrdup(phpurl->fragment); + phpurl = new_url; + + efree(auth); + efree(http_headers); + efree(http_body); + + goto try_again; + } + } + if (auth) efree(auth); + } + /* Check and see if the server even sent a xml document */ content_type = get_http_header_value(http_headers,"Content-Type: "); if (content_type) {
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php