diff --git a/ext/libxml/php_libxml2.def b/ext/libxml/php_libxml2.def index f4be787c8abde..8dcc583048e80 100644 --- a/ext/libxml/php_libxml2.def +++ b/ext/libxml/php_libxml2.def @@ -1547,3 +1547,5 @@ xmlXPtrWrapLocationSet xmlBufContent xmlBufUse xmlBufferDetach +xmlOutputBufferGetContent +xmlOutputBufferGetSize diff --git a/ext/soap/config.m4 b/ext/soap/config.m4 index 8e5fdd4ebcd24..6ed00d54f7c41 100644 --- a/ext/soap/config.m4 +++ b/ext/soap/config.m4 @@ -11,7 +11,7 @@ if test "$PHP_SOAP" != "no"; then PHP_SETUP_LIBXML(SOAP_SHARED_LIBADD, [ AC_DEFINE(HAVE_SOAP,1,[ ]) - PHP_NEW_EXTENSION(soap, soap.c php_encoding.c php_http.c php_packet_soap.c php_schema.c php_sdl.c php_xml.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) + PHP_NEW_EXTENSION(soap, soap.c php_encoding.c php_http.c php_packet_soap.c php_schema.c php_sdl.c php_wss.c php_xml.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_SUBST(SOAP_SHARED_LIBADD) ]) fi diff --git a/ext/soap/config.w32 b/ext/soap/config.w32 index 44c69d8acb5aa..e24b0b1708475 100644 --- a/ext/soap/config.w32 +++ b/ext/soap/config.w32 @@ -8,7 +8,7 @@ if (PHP_SOAP != "no") { CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_SOAP", PHP_PHP_BUILD + "\\include\\libxml2") && CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_SOAP", PHP_PHP_BUILD + "\\include\\libxml2") ) { - EXTENSION('soap', 'soap.c php_encoding.c php_http.c php_packet_soap.c php_schema.c php_sdl.c php_xml.c', null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + EXTENSION('soap', 'soap.c php_encoding.c php_http.c php_packet_soap.c php_schema.c php_sdl.c php_wss.c php_xml.c', null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE('HAVE_PHP_SOAP', 1, "SOAP support"); if (!PHP_SOAP_SHARED) { diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index 33a071ed41819..6499126a34b7a 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -67,6 +67,7 @@ typedef struct _soapService soapService, *soapServicePtr; #include "php_schema.h" #include "php_http.h" #include "php_packet_soap.h" +#include "php_wss.h" struct _soapMapping { zval to_xml; @@ -252,5 +253,13 @@ static zend_always_inline zval *php_soap_deref(zval *zv) { #define Z_CLIENT_LAST_RESPONSE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 33)) #define Z_CLIENT_LAST_REQUEST_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 34)) #define Z_CLIENT_LAST_RESPONSE_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 35)) +#define Z_CLIENT_WSS_SET_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 36)) +#define Z_CLIENT_WSS_SIGNFUNC_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 37)) +#define Z_CLIENT_WSS_X509_BINSECTOKEN_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 38)) +#define Z_CLIENT_WSS_ADD_TIMESTAMP_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 39)) +#define Z_CLIENT_WSS_TIMESTAMP_EXPIRES_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 40)) +#define Z_CLIENT_WSS_DIGEST_METHOD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 41)) +#define Z_CLIENT_WSS_VERSION_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 42)) +#define Z_CLIENT_WSS_RANDOM_ID_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 43)) #endif diff --git a/ext/soap/php_wss.c b/ext/soap/php_wss.c new file mode 100644 index 0000000000000..c4345d74e7ebc --- /dev/null +++ b/ext/soap/php_wss.c @@ -0,0 +1,279 @@ +#include "php_soap.h" +#include "ext/date/php_date.h" +#include "ext/hash/php_hash.h" +#include "ext/standard/base64.h" +#include "ext/standard/php_mt_rand.h" +#include +#include + +static zend_string *get_exc_c14n_from_node_ptr(xmlNodePtr node) /* {{{ */ +{ + zend_string *result = NULL; + + xmlOutputBufferPtr buffer = xmlAllocOutputBuffer(NULL); + if (buffer != NULL) { + xmlXPathContextPtr xpath_ctx = xmlXPathNewContext(node->doc); + if(xpath_ctx != NULL) { + xpath_ctx->node = node; + xmlXPathObjectPtr xpath_obj = xmlXPathEvalExpression(BAD_CAST("(.//. | .//@* | .//namespace::*)"), xpath_ctx); + xpath_ctx->node = NULL; + + if (xpath_obj != NULL && xpath_obj->type == XPATH_NODESET) { + int c14n_ret = xmlC14NDocSaveTo(node->doc, xpath_obj->nodesetval, XML_C14N_EXCLUSIVE_1_0, NULL, 0, buffer); + if (c14n_ret >= 0) { + #ifdef LIBXML2_NEW_BUFFER + int buffer_size = xmlOutputBufferGetSize(buffer); + #else + int buffer_size = buffer->buffer->use; + #endif + if (buffer_size > 0) { + #ifdef LIBXML2_NEW_BUFFER + char *buffer_content = (char *)xmlOutputBufferGetContent(buffer); + #else + char *buffer_content = (char *)buffer->buffer->content; + #endif + result = zend_string_init(buffer_content, strlen(buffer_content), 0); + } + } + } + + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_ctx); + } + xmlOutputBufferClose(buffer); + } + + return result; +} +/* }}} */ + +static int add_reference_to_signed_info(zval *this_ptr, xmlNodePtr signed_info, xmlNodePtr source, zend_string *source_uri, xmlNsPtr ns_ds) /* {{{ */ +{ + xmlNodePtr reference = xmlNewChild(signed_info, ns_ds, BAD_CAST("Reference"), NULL); + xmlSetProp(reference, BAD_CAST("URI"), BAD_CAST(ZSTR_VAL(source_uri))); + xmlNodePtr reference_trsfrms = xmlNewChild(reference, ns_ds, BAD_CAST("Transforms"), NULL); + xmlNodePtr reference_trsfrm = xmlNewChild(reference_trsfrms, ns_ds, BAD_CAST("Transform"), NULL); + xmlSetProp(reference_trsfrm, BAD_CAST("Algorithm"), BAD_CAST(SOAP_WSS_EXC_C14N)); + xmlNodePtr reference_dm = xmlNewChild(reference, ns_ds, BAD_CAST("DigestMethod"), NULL); + + const php_hash_ops *ops = NULL; + zend_string *algo = NULL; + zend_long digest_method = Z_LVAL_P(Z_CLIENT_WSS_DIGEST_METHOD_P(this_ptr)); + switch (digest_method) { + case SOAP_WSS_DIGEST_METHOD_SHA1: + algo = zend_string_init("sha1", strlen("sha1"), 0); + ops = php_hash_fetch_ops(algo); + xmlSetProp(reference_dm, BAD_CAST("Algorithm"), BAD_CAST(SOAP_WSS_SHA1)); + break; + case SOAP_WSS_DIGEST_METHOD_SHA256: + algo = zend_string_init("sha256", strlen("sha256"), 0); + ops = php_hash_fetch_ops(algo); + xmlSetProp(reference_dm, BAD_CAST("Algorithm"), BAD_CAST(SOAP_WSS_SHA256)); + break; + case SOAP_WSS_DIGEST_METHOD_SHA512: + algo = zend_string_init("sha512", strlen("sha512"), 0); + ops = php_hash_fetch_ops(algo); + xmlSetProp(reference_dm, BAD_CAST("Algorithm"), BAD_CAST(SOAP_WSS_SHA512)); + break; + } + + if (ops == NULL) { + if (algo != NULL) { + php_error_docref(NULL, E_WARNING, "invalid hashing algorithm, %s", ZSTR_VAL(algo)); + zend_string_release_ex(algo, 0); + } else { + php_error_docref(NULL, E_WARNING, "unknown hashing algorithm"); + } + return 0; + } + + zend_string_release_ex(algo, 0); + + zend_string *exc_c14n = get_exc_c14n_from_node_ptr(source); + if (exc_c14n != NULL) { + void *context = php_hash_alloc_context(ops); + ops->hash_init(context, NULL); + ops->hash_update(context, (unsigned char *)ZSTR_VAL(exc_c14n), ZSTR_LEN(exc_c14n)); + + zend_string *digest = zend_string_alloc(ops->digest_size, 0); + ops->hash_final((unsigned char *)ZSTR_VAL(digest), context); + efree(context); + + ZSTR_VAL(digest)[ops->digest_size] = 0; + + zend_string *digest_base64 = php_base64_encode((unsigned char *)ZSTR_VAL(digest), ZSTR_LEN(digest)); + xmlNewChild(reference, ns_ds, BAD_CAST("DigestValue"), BAD_CAST(ZSTR_VAL(digest_base64))); + + zend_string_release(digest_base64); + zend_string_release(digest); + zend_string_release_ex(exc_c14n, 0); + + return 1; + } else { + php_error_docref(NULL, E_WARNING, "exclusive C14N failed, URI \"%s\"", ZSTR_VAL(source_uri)); + return 0; + } +} +/* }}} */ + +void add_wss_to_function_call(zval *this_ptr, int soap_version, xmlNodePtr envelope, xmlNodePtr head, xmlNodePtr body) /* {{{ */ +{ + char random_s[10]; + if (Z_TYPE_P(Z_CLIENT_WSS_RANDOM_ID_P(this_ptr)) == IS_TRUE) { + slprintf(random_s, sizeof(random_s), "%d", (int)php_mt_rand_common(100000000,999999999)); + } else { + slprintf(random_s, sizeof(random_s), "%d", 1); + } + + zend_string *body_id = zend_string_concat2( + "BodyID-", strlen("BodyID-"), + random_s, strlen(random_s)); + zend_string *body_id_uri = zend_string_concat2( + "#", strlen("#"), + ZSTR_VAL(body_id), ZSTR_LEN(body_id)); + + xmlNsPtr ns_wsse = NULL; + if (Z_LVAL_P(Z_CLIENT_WSS_VERSION_P(this_ptr)) == SOAP_WSS_VERSION_1_1) { + ns_wsse = xmlNewNs(envelope, BAD_CAST(SOAP_WSS_SECEXT_1_1), BAD_CAST("wsse11")); + } else { + ns_wsse = xmlNewNs(envelope, BAD_CAST(SOAP_WSS_SECEXT_1_0), BAD_CAST("wsse")); + } + + xmlNsPtr ns_ds = xmlNewNs(envelope, BAD_CAST(SOAP_WSS_XMLDSIG), BAD_CAST("ds")); + xmlNsPtr ns_wsu = xmlNewNs(envelope, BAD_CAST(SOAP_WSS_UTILITY), BAD_CAST("wsu")); + xmlNodePtr security = xmlNewChild(head, ns_wsse, BAD_CAST("Security"), NULL); + xmlSetNsProp(body, ns_wsu, BAD_CAST("Id"), BAD_CAST(ZSTR_VAL(body_id))); + + if (soap_version == SOAP_1_1) { + xmlSetProp(security, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("1")); + } else { + xmlSetProp(security, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("true")); + } + + xmlNodePtr timestamp = NULL; + zend_string *timestamp_id = NULL, *timestamp_id_uri = NULL; + if (Z_TYPE_P(Z_CLIENT_WSS_ADD_TIMESTAMP_P(this_ptr)) == IS_TRUE) { + char *time_format = "Y-m-d\\TH:i:s\\Z"; + zend_long now = (zend_long)php_time(); + zend_long expires = Z_LVAL_P(Z_CLIENT_WSS_TIMESTAMP_EXPIRES_P(this_ptr)); + zend_string *timestamp_s = php_format_date(time_format, strlen(time_format), now, 0); + zend_string *expires_s = php_format_date(time_format, strlen(time_format), (now + expires), 0); + + timestamp_id = zend_string_concat2( + "TimestampID-", strlen("TimestampID-"), + random_s, strlen(random_s)); + timestamp_id_uri = zend_string_concat2( + "#", strlen("#"), + ZSTR_VAL(timestamp_id), ZSTR_LEN(timestamp_id)); + + timestamp = xmlNewChild(security, ns_wsu, BAD_CAST("Timestamp"), NULL); + xmlSetNsProp(timestamp, ns_wsu, BAD_CAST("Id"), BAD_CAST(ZSTR_VAL(timestamp_id))); + xmlNewChild(timestamp, ns_wsu, BAD_CAST("Created"), BAD_CAST(ZSTR_VAL(timestamp_s))); + xmlNewChild(timestamp, ns_wsu, BAD_CAST("Expires"), BAD_CAST(ZSTR_VAL(expires_s))); + + zend_string_release(expires_s); + zend_string_release(timestamp_s); + } + + int references = 0; + xmlNodePtr signed_info, signature_value = NULL; + if (Z_TYPE_P(Z_CLIENT_WSS_SIGNFUNC_P(this_ptr)) != IS_NULL) { + zend_string *token_id = NULL, *token_id_uri = NULL; + if (Z_TYPE_P(Z_CLIENT_WSS_X509_BINSECTOKEN_P(this_ptr)) == IS_STRING) { + token_id = zend_string_concat2( + "TokenID-", strlen("TokenID-"), + random_s, strlen(random_s)); + token_id_uri = zend_string_concat2( + "#", strlen("#"), + ZSTR_VAL(token_id), ZSTR_LEN(token_id)); + + zend_string *token_base64 = php_base64_encode((unsigned char *)Z_STRVAL_P(Z_CLIENT_WSS_X509_BINSECTOKEN_P(this_ptr)), Z_STRLEN_P(Z_CLIENT_WSS_X509_BINSECTOKEN_P(this_ptr))); + + xmlNodePtr x509_binsectoken = xmlNewChild(security, ns_wsse, BAD_CAST("BinarySecurityToken"), BAD_CAST(ZSTR_VAL(token_base64))); + xmlSetProp(x509_binsectoken, BAD_CAST("EncodingType"), BAD_CAST(SOAP_WSS_BASE64_BINARY)); + xmlSetProp(x509_binsectoken, BAD_CAST("ValueType"), BAD_CAST(SOAP_WSS_X509v3_TOKEN_PROFILE)); + xmlSetNsProp(x509_binsectoken, ns_wsu, BAD_CAST("Id"), BAD_CAST(ZSTR_VAL(token_id))); + + zend_string_release(token_base64); + } + + xmlNodePtr signature = xmlNewChild(security, ns_ds, BAD_CAST("Signature"), NULL); + signed_info = xmlNewChild(signature, ns_ds, BAD_CAST("SignedInfo"), NULL); + xmlNodePtr canon_method = xmlNewChild(signed_info, ns_ds, BAD_CAST("CanonicalizationMethod"), NULL); + xmlNodePtr sign_method = xmlNewChild(signed_info, ns_ds, BAD_CAST("SignatureMethod"), NULL); + xmlSetProp(canon_method, BAD_CAST("Algorithm"), BAD_CAST(SOAP_WSS_EXC_C14N)); + xmlSetProp(sign_method, BAD_CAST("Algorithm"), BAD_CAST(SOAP_WSS_RSA_SHA1)); + + if (timestamp != NULL) { + references += add_reference_to_signed_info(this_ptr, signed_info, timestamp, timestamp_id_uri, ns_ds); + } + references += add_reference_to_signed_info(this_ptr, signed_info, body, body_id_uri, ns_ds); + + signature_value = xmlNewChild(signature, ns_ds, BAD_CAST("SignatureValue"), NULL); + + if (token_id != NULL) { + xmlNodePtr keyinfo = xmlNewChild(signature, ns_ds, BAD_CAST("KeyInfo"), NULL); + xmlNodePtr keyinfo_sectoken_reference = xmlNewChild(keyinfo, ns_wsse, BAD_CAST("SecurityTokenReference"), NULL); + xmlNodePtr keyinfo_sectoken_reference_ref = xmlNewChild(keyinfo_sectoken_reference, ns_wsse, BAD_CAST("Reference"), NULL); + xmlSetProp(keyinfo_sectoken_reference_ref, BAD_CAST("URI"), BAD_CAST(ZSTR_VAL(token_id_uri))); + xmlSetProp(keyinfo_sectoken_reference_ref, BAD_CAST("ValueType"), BAD_CAST(SOAP_WSS_X509v3_TOKEN_PROFILE)); + zend_string_release_ex(token_id_uri, 0); + zend_string_release_ex(token_id, 0); + } + } + + if (timestamp_id != NULL) { + zend_string_release_ex(timestamp_id_uri, 0); + zend_string_release_ex(timestamp_id, 0); + } + + bool bailout = 0; + if (references != 0) { + zend_string *signed_info_exc_c14n = get_exc_c14n_from_node_ptr(signed_info); + if (signed_info_exc_c14n != NULL) { + zend_fcall_info signature_fci; + zend_fcall_info_cache signature_fcc; + if (zend_fcall_info_init(Z_CLIENT_WSS_SIGNFUNC_P(this_ptr), 0, &signature_fci, &signature_fcc, NULL, NULL) == SUCCESS) { + zval signature_params, signature_retval; + + ZVAL_STR(&signature_params, signed_info_exc_c14n); + + signature_fci.param_count = 1; + signature_fci.params = &signature_params; + signature_fci.retval = &signature_retval; + + if (zend_call_function(&signature_fci, &signature_fcc) == SUCCESS) { + if (Z_TYPE(signature_retval) == IS_STRING) { + zend_string *signature_base64 = php_base64_encode((unsigned char *)Z_STRVAL(signature_retval), Z_STRLEN(signature_retval)); + xmlNodeSetContent(signature_value, BAD_CAST(ZSTR_VAL(signature_base64))); + zend_string_release(signature_base64); + } else { + if (!EG(exception)) { + php_error_docref(NULL, E_WARNING, "\"signfunc\" should return a string, %s given", zend_zval_type_name(&signature_retval)); + } else { + bailout = 1; + } + } + } else { + php_error_docref(NULL, E_WARNING, "unable to run \"signfunc\""); + } + + zval_ptr_dtor_str(&signature_params); + zval_ptr_dtor(&signature_retval); + } else { + php_error_docref(NULL, E_WARNING, "unable to initialize \"signfunc\""); + zend_string_release_ex(signed_info_exc_c14n, 0); + } + } else { + php_error_docref(NULL, E_WARNING, "exclusive C14N failed, element \"SignedInfo\""); + } + } + + zend_string_release_ex(body_id_uri, 0); + zend_string_release_ex(body_id, 0); + + if (bailout) { + zend_bailout(); + } +} +/* }}} */ diff --git a/ext/soap/php_wss.h b/ext/soap/php_wss.h new file mode 100644 index 0000000000000..6f7c06f9bb882 --- /dev/null +++ b/ext/soap/php_wss.h @@ -0,0 +1,27 @@ +#ifndef PHP_WSS_H +#define PHP_WSS_H + +#define SOAP_WSS_DIGEST_METHOD_SHA1 1 +#define SOAP_WSS_DIGEST_METHOD_SHA256 2 +#define SOAP_WSS_DIGEST_METHOD_SHA512 3 + +#define SOAP_WSS_VERSION_1_0 1 +#define SOAP_WSS_VERSION_1_1 2 + +#define SOAP_WSS_TIMESTAMP_EXPIRES 300 + +#define SOAP_WSS_BASE64_BINARY "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" +#define SOAP_WSS_EXC_C14N "http://www.w3.org/2001/10/xml-exc-c14n#" +#define SOAP_WSS_RSA_SHA1 "http://www.w3.org/2000/09/xmldsig#rsa-sha1" +#define SOAP_WSS_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1" +#define SOAP_WSS_SHA256 "http://www.w3.org/2001/04/xmlenc#sha256" +#define SOAP_WSS_SHA512 "http://www.w3.org/2001/04/xmlenc#sha512" +#define SOAP_WSS_SECEXT_1_0 "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" +#define SOAP_WSS_SECEXT_1_1 "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" +#define SOAP_WSS_UTILITY "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" +#define SOAP_WSS_X509v3_TOKEN_PROFILE "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" +#define SOAP_WSS_XMLDSIG "http://www.w3.org/2000/09/xmldsig#" + +void add_wss_to_function_call(zval *this_ptr, int soap_version, xmlNodePtr envelope, xmlNodePtr head, xmlNodePtr body); + +#endif diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 09c82e8255fa2..91145cba09a55 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -522,6 +522,14 @@ PHP_MINIT_FUNCTION(soap) REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv3", SOAP_SSL_METHOD_SSLv3, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv23", SOAP_SSL_METHOD_SSLv23, CONST_CS | CONST_PERSISTENT); + /* SOAP WSS Constants */ + REGISTER_LONG_CONSTANT("SOAP_WSS_DIGEST_METHOD_SHA1", SOAP_WSS_DIGEST_METHOD_SHA1, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_WSS_DIGEST_METHOD_SHA256", SOAP_WSS_DIGEST_METHOD_SHA256, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_WSS_DIGEST_METHOD_SHA512", SOAP_WSS_DIGEST_METHOD_SHA512, CONST_CS | CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("SOAP_WSS_VERSION_1_0", SOAP_WSS_VERSION_1_0, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_WSS_VERSION_1_1", SOAP_WSS_VERSION_1_1, CONST_CS | CONST_PERSISTENT); + old_error_handler = zend_error_cb; zend_error_cb = soap_error_handler; @@ -2805,6 +2813,169 @@ PHP_METHOD(SoapClient, __setLocation) } /* }}} */ +/* {{{ Sets SOAP WSS headers for subsequent calls (replaces any previous + values). + If no value is specified, SOAP WSS headers are removed. */ +PHP_METHOD(SoapClient, __setWSS) +{ + zval *options = NULL; + zval *this_ptr = ZEND_THIS; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &options) == FAILURE) { + RETURN_THROWS(); + } + + bool processed = 0, success = 1, wss_set = 0; + + cleanup: + if (!processed || wss_set) { + ZVAL_FALSE(Z_CLIENT_WSS_SET_P(this_ptr)); + convert_to_null(Z_CLIENT_WSS_SIGNFUNC_P(this_ptr)); + convert_to_null(Z_CLIENT_WSS_X509_BINSECTOKEN_P(this_ptr)); + ZVAL_FALSE(Z_CLIENT_WSS_ADD_TIMESTAMP_P(this_ptr)); + convert_to_null(Z_CLIENT_WSS_TIMESTAMP_EXPIRES_P(this_ptr)); + convert_to_null(Z_CLIENT_WSS_DIGEST_METHOD_P(this_ptr)); + convert_to_null(Z_CLIENT_WSS_VERSION_P(this_ptr)); + ZVAL_TRUE(Z_CLIENT_WSS_RANDOM_ID_P(this_ptr)); + } + + if (options != NULL && !processed) { + HashTable *ht = Z_ARRVAL_P(options); + zval *tmp = NULL; + processed = 1; + + if ((tmp = zend_hash_str_find(ht, "signfunc", sizeof("signfunc")-1)) != NULL + && Z_TYPE_P(tmp) != IS_NULL) { + char *is_callable_error = NULL; + zend_fcall_info fci; + zend_fcall_info_cache fcc; + + if (zend_fcall_info_init(tmp, 0, &fci, &fcc, NULL, &is_callable_error) == SUCCESS) { + ZEND_ASSERT(!is_callable_error); + zend_release_fcall_info_cache(&fcc); + ZVAL_COPY(Z_CLIENT_WSS_SIGNFUNC_P(this_ptr), tmp); + wss_set = 1; + + if ((tmp = zend_hash_str_find(ht, "x509_binsectoken", sizeof("x509_binsectoken")-1)) != NULL) { + if (Z_TYPE_P(tmp) == IS_STRING) { + if (Z_STRLEN_P(tmp) != 0) { + ZVAL_COPY(Z_CLIENT_WSS_X509_BINSECTOKEN_P(this_ptr), tmp); + } + } else if (Z_TYPE_P(tmp) != IS_NULL) { + zend_type_error("%s(): \"x509_binsectoken\" must be of type string or null, %s given", get_active_function_name(), zend_zval_type_name(tmp)); + success = 0; + goto cleanup; + } + } + + if ((tmp = zend_hash_str_find(ht, "digest_method", sizeof("digest_method")-1)) != NULL) { + if (Z_TYPE_P(tmp) == IS_LONG) { + zend_long digest_method = Z_LVAL_P(tmp); + switch (digest_method) { + case SOAP_WSS_DIGEST_METHOD_SHA1: + case SOAP_WSS_DIGEST_METHOD_SHA256: + case SOAP_WSS_DIGEST_METHOD_SHA512: + ZVAL_LONG(Z_CLIENT_WSS_DIGEST_METHOD_P(this_ptr), digest_method); + break; + default: + zend_value_error("%s(): invalid \"digest_method\" value, %d given", get_active_function_name(), (int)digest_method); + success = 0; + goto cleanup; + } + } else { + zend_type_error("%s(): \"digest_method\" must be of type int, %s given", get_active_function_name(), zend_zval_type_name(tmp)); + success = 0; + goto cleanup; + } + } else { + ZVAL_LONG(Z_CLIENT_WSS_DIGEST_METHOD_P(this_ptr), SOAP_WSS_DIGEST_METHOD_SHA1); + } + } else { + if (is_callable_error != NULL) { + zend_type_error("%s(): \"signfunc\" must be a valid callback or null, %s", get_active_function_name(), is_callable_error); + efree(is_callable_error); + } else { + zend_type_error("%s(): \"signfunc\" must be a valid callback or null", get_active_function_name()); + } + success = 0; + goto cleanup; + } + } + + if ((tmp = zend_hash_str_find(ht, "add_timestamp", sizeof("add_timestamp")-1)) != NULL) { + if (Z_TYPE_P(tmp) == IS_TRUE) { + ZVAL_TRUE(Z_CLIENT_WSS_ADD_TIMESTAMP_P(this_ptr)); + wss_set = 1; + + if ((tmp = zend_hash_str_find(ht, "timestamp_expires", sizeof("timestamp_expires")-1)) != NULL) { + if (Z_TYPE_P(tmp) == IS_LONG) { + zend_long timestamp_expires = Z_LVAL_P(tmp); + if (timestamp_expires >= 0 && timestamp_expires <= 7200) { + ZVAL_LONG(Z_CLIENT_WSS_TIMESTAMP_EXPIRES_P(this_ptr), timestamp_expires); + } else { + zend_value_error("%s(): invalid \"timestamp_expires\" value, %d given", get_active_function_name(), (int)timestamp_expires); + success = 0; + goto cleanup; + } + } else { + zend_type_error("%s(): \"timestamp_expires\" must be of type int, %s given", get_active_function_name(), zend_zval_type_name(tmp)); + success = 0; + goto cleanup; + } + } else { + ZVAL_LONG(Z_CLIENT_WSS_TIMESTAMP_EXPIRES_P(this_ptr), SOAP_WSS_TIMESTAMP_EXPIRES); + } + } else if (Z_TYPE_P(tmp) != IS_FALSE) { + zend_type_error("%s(): \"add_timestamp\" must be of type bool, %s given", get_active_function_name(), zend_zval_type_name(tmp)); + success = 0; + goto cleanup; + } + } + + if ((tmp = zend_hash_str_find(ht, "random_id", sizeof("random_id")-1)) != NULL) { + if (Z_TYPE_P(tmp) == IS_FALSE) { + ZVAL_FALSE(Z_CLIENT_WSS_RANDOM_ID_P(this_ptr)); + } else if (Z_TYPE_P(tmp) != IS_TRUE) { + zend_type_error("%s(): \"random_id\" must be of type bool, %s given", get_active_function_name(), zend_zval_type_name(tmp)); + success = 0; + goto cleanup; + } + } + + if (success && wss_set) { + if ((tmp = zend_hash_str_find(ht, "wss_version", sizeof("wss_version")-1)) != NULL) { + if (Z_TYPE_P(tmp) == IS_LONG) { + zend_long wss_version = Z_LVAL_P(tmp); + switch (wss_version) { + case SOAP_WSS_VERSION_1_0: + case SOAP_WSS_VERSION_1_1: + ZVAL_LONG(Z_CLIENT_WSS_VERSION_P(this_ptr), wss_version); + break; + default: + zend_value_error("%s(): invalid \"wss_version\" value, %d given", get_active_function_name(), (int)wss_version); + success = 0; + goto cleanup; + } + } else { + zend_type_error("%s(): \"wss_version\" must be of type int, %s given", get_active_function_name(), zend_zval_type_name(tmp)); + success = 0; + goto cleanup; + } + } else { + ZVAL_LONG(Z_CLIENT_WSS_VERSION_P(this_ptr), SOAP_WSS_VERSION_1_0); + } + ZVAL_TRUE(Z_CLIENT_WSS_SET_P(this_ptr)); + } + } + + if (success) { + RETURN_TRUE; + } else { + RETURN_THROWS(); + } +} +/* }}} */ + static void clear_soap_fault(zval *obj) /* {{{ */ { ZEND_ASSERT(instanceof_function(Z_OBJCE_P(obj), soap_class_entry)); @@ -3794,6 +3965,11 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function zval *zstyle, *zuse; int i, style, use; HashTable *hdrs = NULL; + bool wss_set = 0; + + if (Z_TYPE_P(Z_CLIENT_WSS_SET_P(this_ptr)) == IS_TRUE) { + wss_set = 1; + } encode_reset_ns(); @@ -3815,7 +3991,7 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function } xmlDocSetRootElement(doc, envelope); - if (soap_headers) { + if (soap_headers || wss_set) { head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL); } @@ -3911,9 +4087,13 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function } } - if (head) { - zval* header; + if (head && wss_set) { + add_wss_to_function_call(this_ptr, version, envelope, head, body); + } + if (head && soap_headers) { + zval* header; + ZEND_HASH_FOREACH_VAL(soap_headers, header) { if (Z_TYPE_P(header) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(header), soap_header_class_entry)) { diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index d21b715cd7580..1c1ea0e03cfe5 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -130,6 +130,14 @@ class SoapClient private ?string $__last_response = null; private ?string $__last_request_headers = null; private ?string $__last_response_headers = null; + private bool $_wss_set = false; + private ?callable $_wss_signfunc = null; + private ?string $_wss_x509_binsectoken = null; + private bool $_wss_add_timestamp = false; + private ?int $_wss_timestamp_expires = null; + private ?int $_wss_digest_method = null; + private ?int $_wss_version = null; + private bool $_wss_random_id = true; public function __construct(?string $wsdl, array $options = []) {} @@ -178,4 +186,7 @@ public function __setSoapHeaders($headers = null): bool {} /** @tentative-return-type */ public function __setLocation(?string $location = null): ?string {} + + /** @tentative-return-type */ + public function __setWSS(?array $options = null): bool {} } diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index eed9247072cd5..13c8c6d1251ce 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 96c82014f1fe922cee14d0cd55dd14a6ba3ffe5f */ + * Stub hash: 653d3384207f336026346fcfc531ee40cf0fa5dd */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true") @@ -136,6 +136,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___set ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, location, IS_STRING, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___setWSS, 0, 0, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") +ZEND_END_ARG_INFO() + ZEND_FUNCTION(use_soap_error_handler); ZEND_FUNCTION(is_soap_fault); @@ -167,6 +171,7 @@ ZEND_METHOD(SoapClient, __setCookie); ZEND_METHOD(SoapClient, __getCookies); ZEND_METHOD(SoapClient, __setSoapHeaders); ZEND_METHOD(SoapClient, __setLocation); +ZEND_METHOD(SoapClient, __setWSS); static const zend_function_entry ext_functions[] = { @@ -230,6 +235,7 @@ static const zend_function_entry class_SoapClient_methods[] = { ZEND_ME(SoapClient, __getCookies, arginfo_class_SoapClient___getCookies, ZEND_ACC_PUBLIC) ZEND_ME(SoapClient, __setSoapHeaders, arginfo_class_SoapClient___setSoapHeaders, ZEND_ACC_PUBLIC) ZEND_ME(SoapClient, __setLocation, arginfo_class_SoapClient___setLocation, ZEND_ACC_PUBLIC) + ZEND_ME(SoapClient, __setWSS, arginfo_class_SoapClient___setWSS, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -634,5 +640,53 @@ static zend_class_entry *register_class_SoapClient(void) zend_declare_typed_property(class_entry, property___last_response_headers_name, &property___last_response_headers_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zend_string_release(property___last_response_headers_name); + zval property__wss_set_default_value; + ZVAL_BOOL(&property__wss_set_default_value, 0); + zend_string *property__wss_set_name = zend_string_init("_wss_set", sizeof("_wss_set") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_set_name, &property__wss_set_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property__wss_set_name); + + zval property__wss_signfunc_default_value; + ZVAL_NULL(&property__wss_signfunc_default_value); + zend_string *property__wss_signfunc_name = zend_string_init("_wss_signfunc", sizeof("_wss_signfunc") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_signfunc_name, &property__wss_signfunc_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_CALLABLE|MAY_BE_NULL)); + zend_string_release(property__wss_signfunc_name); + + zval property__wss_x509_binsectoken_default_value; + ZVAL_NULL(&property__wss_x509_binsectoken_default_value); + zend_string *property__wss_x509_binsectoken_name = zend_string_init("_wss_x509_binsectoken", sizeof("_wss_x509_binsectoken") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_x509_binsectoken_name, &property__wss_x509_binsectoken_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string_release(property__wss_x509_binsectoken_name); + + zval property__wss_add_timestamp_default_value; + ZVAL_BOOL(&property__wss_add_timestamp_default_value, 0); + zend_string *property__wss_add_timestamp_name = zend_string_init("_wss_add_timestamp", sizeof("_wss_add_timestamp") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_add_timestamp_name, &property__wss_add_timestamp_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property__wss_add_timestamp_name); + + zval property__wss_timestamp_expires_default_value; + ZVAL_NULL(&property__wss_timestamp_expires_default_value); + zend_string *property__wss_timestamp_expires_name = zend_string_init("_wss_timestamp_expires", sizeof("_wss_timestamp_expires") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_timestamp_expires_name, &property__wss_timestamp_expires_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); + zend_string_release(property__wss_timestamp_expires_name); + + zval property__wss_digest_method_default_value; + ZVAL_NULL(&property__wss_digest_method_default_value); + zend_string *property__wss_digest_method_name = zend_string_init("_wss_digest_method", sizeof("_wss_digest_method") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_digest_method_name, &property__wss_digest_method_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); + zend_string_release(property__wss_digest_method_name); + + zval property__wss_version_default_value; + ZVAL_NULL(&property__wss_version_default_value); + zend_string *property__wss_version_name = zend_string_init("_wss_version", sizeof("_wss_version") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_version_name, &property__wss_version_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); + zend_string_release(property__wss_version_name); + + zval property__wss_random_id_default_value; + ZVAL_BOOL(&property__wss_random_id_default_value, 1); + zend_string *property__wss_random_id_name = zend_string_init("_wss_random_id", sizeof("_wss_random_id") - 1, 1); + zend_declare_typed_property(class_entry, property__wss_random_id_name, &property__wss_random_id_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property__wss_random_id_name); + return class_entry; } diff --git a/ext/soap/tests/wss/T01.phpt b/ext/soap/tests/wss/T01.phpt new file mode 100644 index 0000000000000..5bdfba95427c0 --- /dev/null +++ b/ext/soap/tests/wss/T01.phpt @@ -0,0 +1,59 @@ +--TEST-- +SOAP CLIENT WSS: SOAP 1.1 / WSS 1.0 SHA1 echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setWSS(array( + "random_id" => false, + "x509_binsectoken" => "TEST CERTIFICATE", + "signfunc" => function($data) { + return "TEST SIGNATURE"; + } +)); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%w +%wVEVTVCBDRVJUSUZJQ0FURQ== +%w +%w +%w +%w +%w +%w +%w +%w +%w +%wOaQiUDsEKrCjytgTUqF4CLsB9jo= +%w +%w +%wVEVTVCBTSUdOQVRVUkU= +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T02.phpt b/ext/soap/tests/wss/T02.phpt new file mode 100644 index 0000000000000..92b5bfb749006 --- /dev/null +++ b/ext/soap/tests/wss/T02.phpt @@ -0,0 +1,36 @@ +--TEST-- +SOAP CLIENT WSS: Remove WSS headers echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setWSS(array( + "x509_binsectoken" => "TEST CERTIFICATE", + "signfunc" => function($data) { + return "TEST SIGNATURE"; + } +)); + +$client->__setWSS(); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T03.phpt b/ext/soap/tests/wss/T03.phpt new file mode 100644 index 0000000000000..163fbf7942379 --- /dev/null +++ b/ext/soap/tests/wss/T03.phpt @@ -0,0 +1,27 @@ +--TEST-- +SOAP CLIENT WSS: No WSS headers echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T04.phpt b/ext/soap/tests/wss/T04.phpt new file mode 100644 index 0000000000000..05bcc5e86d599 --- /dev/null +++ b/ext/soap/tests/wss/T04.phpt @@ -0,0 +1,75 @@ +--TEST-- +SOAP CLIENT WSS: SOAP 1.2 / WSS 1.1 SHA256 with timestamp and random id echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- + SOAP_1_2 +)); + +$client->__setWSS(array( + "add_timestamp" => true, + "timestamp_expires" => 300, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "wss_version" => SOAP_WSS_VERSION_1_1, + "x509_binsectoken" => "TEST CERTIFICATE", + "signfunc" => function($data) { + return "TEST SIGNATURE"; + } +)); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%w +%w +%w%r([0-9]{4})%r-%r([0-9]{2})%r-%r([0-9]{2})%rT%r([0-9]{2})%r:%r([0-9]{2})%r:%r([0-9]{2})%rZ +%w%r([0-9]{4})%r-%r([0-9]{2})%r-%r([0-9]{2})%rT%r([0-9]{2})%r:%r([0-9]{2})%r:%r([0-9]{2})%rZ +%w +%w%s +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w%s +%w +%w +%w +%w +%w +%w +%w%s +%w +%w +%w%s +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T05.phpt b/ext/soap/tests/wss/T05.phpt new file mode 100644 index 0000000000000..78b40b925cc06 --- /dev/null +++ b/ext/soap/tests/wss/T05.phpt @@ -0,0 +1,76 @@ +--TEST-- +SOAP CLIENT WSS: SOAP 1.1 / WSS 1.1 SHA512 with additional header echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setWSS(array( + "random_id" => false, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA512, + "wss_version" => SOAP_WSS_VERSION_1_1, + "x509_binsectoken" => "TEST CERTIFICATE", + "signfunc" => function($data) { + return "TEST SIGNATURE"; + } +)); + +$client->__setSoapHeaders(array( + new SoapHeader( + 'http://localhost/header/', + 'TestHeader1', + 'Hello' + ), + new SoapHeader( + 'http://localhost/header/', + 'TestHeader2', + 'World' + ), +)); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%w +%w%s +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w%s +%w +%w +%w%s +%w +%w +%w +%w +%w +%w +%w +%wHello +%wWorld +%w +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T06.phpt b/ext/soap/tests/wss/T06.phpt new file mode 100644 index 0000000000000..b1ea1a1f14b95 --- /dev/null +++ b/ext/soap/tests/wss/T06.phpt @@ -0,0 +1,44 @@ +--TEST-- +SOAP CLIENT WSS: Only additional headers, no WSS headers echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setSoapHeaders(array( + new SoapHeader( + 'http://localhost/header/', + 'TestHeader1', + 'Hello' + ), + new SoapHeader( + 'http://localhost/header/', + 'TestHeader2', + 'World' + ), +)); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%wHello +%wWorld +%w +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T07.phpt b/ext/soap/tests/wss/T07.phpt new file mode 100644 index 0000000000000..66093a756cbd3 --- /dev/null +++ b/ext/soap/tests/wss/T07.phpt @@ -0,0 +1,54 @@ +--TEST-- +SOAP CLIENT WSS: SOAP 1.1 / WSS 1.0 SHA1 with user defined function and without binsectoken echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setWSS(array( + "random_id" => false, + "signfunc" => "__wss_test_signfunc" +)); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- + + +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%wOaQiUDsEKrCjytgTUqF4CLsB9jo= +%w +%w +%wVEVTVCBTSUdOQVRVUkU= +%w +%w +%w +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T08.phpt b/ext/soap/tests/wss/T08.phpt new file mode 100644 index 0000000000000..f17c27f694cb2 --- /dev/null +++ b/ext/soap/tests/wss/T08.phpt @@ -0,0 +1,66 @@ +--TEST-- +SOAP CLIENT WSS: SOAP 1.1 / WSS 1.0 SHA1 with user defined class and invalid signature echo +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setWSS(array( + "random_id" => false, + "x509_binsectoken" => "TEST CERTIFICATE", + "signfunc" => array($obj,"sign") +)); + +$client->testFunction(array( + "Param1" => "foo", + "Param2" => "bar" +)); +?> +--EXPECTF-- +Warning: SoapClient::__call(): "signfunc" should return a string, null given in %s on line %d + + +%w +%w +%wVEVTVCBDRVJUSUZJQ0FURQ== +%w +%w +%w +%w +%w +%w +%w +%w +%w +%wOaQiUDsEKrCjytgTUqF4CLsB9jo= +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%w +%wfoo +%wbar +%w +%w + diff --git a/ext/soap/tests/wss/T09.phpt b/ext/soap/tests/wss/T09.phpt new file mode 100644 index 0000000000000..67faaaa0d9e25 --- /dev/null +++ b/ext/soap/tests/wss/T09.phpt @@ -0,0 +1,189 @@ +--TEST-- +SOAP CLIENT WSS: Type and value error handling +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +__setWSS(false); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => "__fail_me" + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => false + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => false, + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => 999, + )); +} catch (ValueError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => null + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => null + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => -1 + )); +} catch (ValueError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => 120, + "random_id" => null + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => 120, + "random_id" => true + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => 120, + "random_id" => true, + "wss_version" => null + )); +} catch (TypeError $e) { + var_dump($e->getMessage()); +} + +try { + $client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => 120, + "random_id" => true, + "wss_version" => 999 + )); +} catch (ValueError $e) { + var_dump($e->getMessage()); +} + +var_dump($client->__setWSS(array( + "signfunc" => function($data) { + return $data; + }, + "x509_binsectoken" => null, + "digest_method" => SOAP_WSS_DIGEST_METHOD_SHA256, + "add_timestamp" => true, + "timestamp_expires" => 120, + "random_id" => true, + "wss_version" => SOAP_WSS_VERSION_1_1 +))); +?> +--EXPECTF-- +string(81) "SoapClient::__setWSS(): Argument #1 ($options) must be of type ?array, bool given" +string(112) "__setWSS(): "signfunc" must be a valid callback or null, function "__fail_me" not found or invalid function name" +string(73) "__setWSS(): "x509_binsectoken" must be of type string or null, bool given" +string(59) "__setWSS(): "digest_method" must be of type int, bool given" +string(52) "__setWSS(): invalid "digest_method" value, 999 given" +string(60) "__setWSS(): "add_timestamp" must be of type bool, null given" +string(63) "__setWSS(): "timestamp_expires" must be of type int, null given" +string(55) "__setWSS(): invalid "timestamp_expires" value, -1 given" +string(56) "__setWSS(): "random_id" must be of type bool, null given" +string(57) "__setWSS(): "wss_version" must be of type int, null given" +string(50) "__setWSS(): invalid "wss_version" value, 999 given" +bool(true) diff --git a/ext/soap/tests/wss/wss-test.inc b/ext/soap/tests/wss/wss-test.inc new file mode 100644 index 0000000000000..2beb75cb87b99 --- /dev/null +++ b/ext/soap/tests/wss/wss-test.inc @@ -0,0 +1,10 @@ +preserveWhiteSpace = false; + $doc->formatOutput = true; + $doc->loadXML($request); + die($doc->saveXML()); + } +} diff --git a/ext/soap/tests/wss/wss-test.wsdl b/ext/soap/tests/wss/wss-test.wsdl new file mode 100644 index 0000000000000..32d6a71035b8b --- /dev/null +++ b/ext/soap/tests/wss/wss-test.wsdl @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +