From a99fdeb9d398c63e915e07230d77c1403c534d88 Mon Sep 17 00:00:00 2001 From: Justin Boswell Date: Tue, 18 May 2021 14:06:26 -0700 Subject: [PATCH] Added bindings for Signable, SigningConfig, Signing (#23) * Added bindings for Signable, SigningConfig, Signing * Fixed PHP5.6 argument vector madness * Added SigningConfigAWS implementation and lifetime tests * Updated .gitignore * Added impl for Signing::signRequestAws(), laid out sigv4 test --- .gitignore | 4 +- ext/awscrt.stub.php | 36 ++ ext/awscrt_arginfo.h | 123 ++++- ext/crt.c | 492 ++++++++++++++---- src/AWS/CRT/Auth/AwsCredentials.php | 20 +- src/AWS/CRT/Auth/Signable.php | 43 ++ src/AWS/CRT/Auth/SignatureType.php | 15 + src/AWS/CRT/Auth/SignedBodyHeaderType.php | 11 + src/AWS/CRT/Auth/Signing.php | 14 + src/AWS/CRT/Auth/SigningAlgorithm.php | 10 + src/AWS/CRT/Auth/SigningConfigAWS.php | 57 ++ .../CRT/Auth/StaticCredentialsProvider.php | 13 +- src/AWS/CRT/CRT.php | 72 +++ src/AWS/CRT/IO/EventLoopGroup.php | 9 +- src/AWS/CRT/NativeResource.php | 4 +- src/AWS/CRT/Options.php | 54 +- tests/SigningTest.php | 87 ++++ 17 files changed, 930 insertions(+), 134 deletions(-) create mode 100644 src/AWS/CRT/Auth/Signable.php create mode 100644 src/AWS/CRT/Auth/SignatureType.php create mode 100644 src/AWS/CRT/Auth/SignedBodyHeaderType.php create mode 100644 src/AWS/CRT/Auth/Signing.php create mode 100644 src/AWS/CRT/Auth/SigningAlgorithm.php create mode 100644 src/AWS/CRT/Auth/SigningConfigAWS.php create mode 100644 tests/SigningTest.php diff --git a/.gitignore b/.gitignore index d1394d2..a4fe3b7 100644 --- a/.gitignore +++ b/.gitignore @@ -82,7 +82,7 @@ _deps .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf - +.idea/ # Generated files .idea/**/contentModel.xml @@ -195,3 +195,5 @@ config.nice Makefile* !Makefile.am /vendor/ +.idea/ +.DS_Store diff --git a/ext/awscrt.stub.php b/ext/awscrt.stub.php index b795083..8e96360 100644 --- a/ext/awscrt.stub.php +++ b/ext/awscrt.stub.php @@ -76,3 +76,39 @@ function aws_crt_credentials_provider_static_options_set_secret_access_key(objec function aws_crt_credentials_provider_static_options_set_session_token(object $options, string $session_token): void {} function aws_crt_credentials_provider_static_new(object $options): object {} + +function aws_crt_signing_config_aws_new(): int {} + +function aws_crt_signing_config_aws_release(int $config): void {} + +function aws_crt_signing_config_aws_set_algorithm(int $config, int $algorithm): void {} + +function aws_crt_signing_config_aws_set_signature_type(int $config, int $signature_type): void {} + +function aws_crt_signing_config_aws_set_credentials_provider(int $config, int $credentials_provider): void {} + +function aws_crt_signing_config_aws_set_region(int $config, string $region): void {} + +function aws_crt_signing_config_aws_set_service(int $config, string $service): void {} + +function aws_crt_signing_config_aws_set_use_double_uri_encode(int $config, bool $use_double_uri_encode): void {} + +function aws_crt_signing_config_aws_set_should_normalize_uri_path(int $config, bool $should_normalize_uri_path): void {} + +function aws_crt_signing_config_aws_set_omit_session_token(int $config, bool $omit_session_token): void {} + +function aws_crt_signing_config_aws_set_signed_body_value(int $config, string $signed_body_value): void {} + +function aws_crt_signing_config_aws_set_signed_body_header_type(int $config, int $signed_body_header_type): void {} + +function aws_crt_signing_config_aws_set_expiration_in_seconds(int $config, int $expiration_in_seconds): void {} + +function aws_crt_signable_new_from_http_request(int $http_message): int {} + +function aws_crt_signable_new_from_chunk(int $input_stream, string $previous_signature): int {} + +function aws_crt_signable_new_from_canonical_request(string $request): int {} + +function aws_crt_signable_release(int $signable): void {} + +function aws_crt_sign_request_aws(int $signable, int $signing_config, object $on_complete, object $user_data): int {} diff --git a/ext/awscrt_arginfo.h b/ext/awscrt_arginfo.h index 9657da2..1446152 100644 --- a/ext/awscrt_arginfo.h +++ b/ext/awscrt_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 5101b351fa7644a60919f40e09b7877a31a6d3bd */ + * Stub hash: 8694d01fdcf4c8ffa26a6462b6c4546671ce7aa5 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_last_error, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -126,6 +126,91 @@ ZEND_END_ARG_INFO() #define arginfo_aws_crt_credentials_provider_static_new arginfo_aws_crt_event_loop_group_new +#define arginfo_aws_crt_signing_config_aws_new arginfo_aws_crt_last_error + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_release, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_algorithm, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, algorithm, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_signature_type, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, signature_type, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_credentials_provider, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, credentials_provider, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_region, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, region, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_service, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, service, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_use_double_uri_encode, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, use_double_uri_encode, _IS_BOOL, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_should_normalize_uri_path, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, should_normalize_uri_path, _IS_BOOL, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_omit_session_token, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, omit_session_token, _IS_BOOL, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_signed_body_value, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, signed_body_value, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_signed_body_header_type, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, signed_body_header_type, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signing_config_aws_set_expiration_in_seconds, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, expiration_in_seconds, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signable_new_from_http_request, 0, 1, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, http_message, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signable_new_from_chunk, 0, 2, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, input_stream, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, previous_signature, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signable_new_from_canonical_request, 0, 1, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, request, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_signable_release, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, signable, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_sign_request_aws, 0, 4, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, signable, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, signing_config, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, on_complete, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, user_data, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + ZEND_FUNCTION(aws_crt_last_error); ZEND_FUNCTION(aws_crt_error_name); @@ -163,6 +248,24 @@ ZEND_FUNCTION(aws_crt_credentials_provider_static_options_set_access_key_id); ZEND_FUNCTION(aws_crt_credentials_provider_static_options_set_secret_access_key); ZEND_FUNCTION(aws_crt_credentials_provider_static_options_set_session_token); ZEND_FUNCTION(aws_crt_credentials_provider_static_new); +ZEND_FUNCTION(aws_crt_signing_config_aws_new); +ZEND_FUNCTION(aws_crt_signing_config_aws_release); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_algorithm); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_signature_type); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_credentials_provider); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_region); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_service); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_use_double_uri_encode); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_should_normalize_uri_path); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_omit_session_token); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_signed_body_value); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_signed_body_header_type); +ZEND_FUNCTION(aws_crt_signing_config_aws_set_expiration_in_seconds); +ZEND_FUNCTION(aws_crt_signable_new_from_http_request); +ZEND_FUNCTION(aws_crt_signable_new_from_chunk); +ZEND_FUNCTION(aws_crt_signable_new_from_canonical_request); +ZEND_FUNCTION(aws_crt_signable_release); +ZEND_FUNCTION(aws_crt_sign_request_aws); static const zend_function_entry ext_functions[] = { @@ -202,5 +305,23 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(aws_crt_credentials_provider_static_options_set_secret_access_key, arginfo_aws_crt_credentials_provider_static_options_set_secret_access_key) ZEND_FE(aws_crt_credentials_provider_static_options_set_session_token, arginfo_aws_crt_credentials_provider_static_options_set_session_token) ZEND_FE(aws_crt_credentials_provider_static_new, arginfo_aws_crt_credentials_provider_static_new) + ZEND_FE(aws_crt_signing_config_aws_new, arginfo_aws_crt_signing_config_aws_new) + ZEND_FE(aws_crt_signing_config_aws_release, arginfo_aws_crt_signing_config_aws_release) + ZEND_FE(aws_crt_signing_config_aws_set_algorithm, arginfo_aws_crt_signing_config_aws_set_algorithm) + ZEND_FE(aws_crt_signing_config_aws_set_signature_type, arginfo_aws_crt_signing_config_aws_set_signature_type) + ZEND_FE(aws_crt_signing_config_aws_set_credentials_provider, arginfo_aws_crt_signing_config_aws_set_credentials_provider) + ZEND_FE(aws_crt_signing_config_aws_set_region, arginfo_aws_crt_signing_config_aws_set_region) + ZEND_FE(aws_crt_signing_config_aws_set_service, arginfo_aws_crt_signing_config_aws_set_service) + ZEND_FE(aws_crt_signing_config_aws_set_use_double_uri_encode, arginfo_aws_crt_signing_config_aws_set_use_double_uri_encode) + ZEND_FE(aws_crt_signing_config_aws_set_should_normalize_uri_path, arginfo_aws_crt_signing_config_aws_set_should_normalize_uri_path) + ZEND_FE(aws_crt_signing_config_aws_set_omit_session_token, arginfo_aws_crt_signing_config_aws_set_omit_session_token) + ZEND_FE(aws_crt_signing_config_aws_set_signed_body_value, arginfo_aws_crt_signing_config_aws_set_signed_body_value) + ZEND_FE(aws_crt_signing_config_aws_set_signed_body_header_type, arginfo_aws_crt_signing_config_aws_set_signed_body_header_type) + ZEND_FE(aws_crt_signing_config_aws_set_expiration_in_seconds, arginfo_aws_crt_signing_config_aws_set_expiration_in_seconds) + ZEND_FE(aws_crt_signable_new_from_http_request, arginfo_aws_crt_signable_new_from_http_request) + ZEND_FE(aws_crt_signable_new_from_chunk, arginfo_aws_crt_signable_new_from_chunk) + ZEND_FE(aws_crt_signable_new_from_canonical_request, arginfo_aws_crt_signable_new_from_canonical_request) + ZEND_FE(aws_crt_signable_release, arginfo_aws_crt_signable_release) + ZEND_FE(aws_crt_sign_request_aws, arginfo_aws_crt_sign_request_aws) ZEND_FE_END }; diff --git a/ext/crt.c b/ext/crt.c index 8ddf71a..816d80f 100644 --- a/ext/crt.c +++ b/ext/crt.c @@ -19,6 +19,178 @@ * libuv extension: https://github.com/amphp/ext-uv/blob/master/php_uv.c */ +/* Macros borrowed from aws-c-common */ +#define GLUE(x, y) x y + +#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count +#define EXPAND_ARGS(args) RETURN_ARG_COUNT args +#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0)) + +#define OVERLOAD_MACRO2(name, count) name##count +#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count) +#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count) + +#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__)) + +#define VARIABLE_LENGTH_ARRAY(type, name, length) type *name = alloca(sizeof(type) * (length)) + +/* + * Exception throwing mechanism, will never return + */ +#define aws_php_throw_exception(...) CALL_OVERLOAD(_AWS_PHP_THROW_EXCEPTION, __VA_ARGS__); +#define _AWS_PHP_THROW_EXCEPTION5(format, ...) zend_error_noreturn(E_ERROR, format, __VA_ARGS__) +#define _AWS_PHP_THROW_EXCEPTION4(format, ...) zend_error_noreturn(E_ERROR, format, __VA_ARGS__) +#define _AWS_PHP_THROW_EXCEPTION3(format, ...) zend_error_noreturn(E_ERROR, format, __VA_ARGS__) +#define _AWS_PHP_THROW_EXCEPTION2(format, ...) zend_error_noreturn(E_ERROR, format, __VA_ARGS__) +#define _AWS_PHP_THROW_EXCEPTION1(format) zend_error_noreturn(E_ERROR, format) + +/** + * throws an exception resulting from argument parsing, notes the current function name in the exception + */ +#define aws_php_argparse_fail() \ + do { \ + aws_php_throw_exception("Failed to parse arguments to %s", __func__); \ + } while (0) + +/** + * calls zend_parse_parameters() with the arguments and throws an exception if parsing fails + */ +#define aws_php_parse_parameters(type_spec, ...) \ + do { \ + if (zend_parse_parameters(ZEND_NUM_ARGS(), type_spec, __VA_ARGS__) == FAILURE) { \ + aws_php_argparse_fail(); \ + } \ + } while (0) + +/** + * calls zend_parse_parameters_none() and throws an exception if parsing fails + */ +#define aws_php_parse_parameters_none() \ + do { \ + if (zend_parse_parameters_none() == FAILURE) { \ + aws_php_argparse_fail(); \ + } \ + } while (0) + +/** + * generic dispatch mechanism to call a callback provided as a zval with arguments + * that are converted to zvals based on the arg_types format string + * Uses the same format string as zend_parse_parameters + */ +static zval *aws_php_invoke_callback(zval *callback, const char *arg_types, ...) { + + char *error = NULL; + zend_fcall_info fci = {0}; + zend_fcall_info_cache fcc = {0}; + if (zend_fcall_info_init(callback, IS_CALLABLE_CHECK_SYNTAX_ONLY, &fci, &fcc, NULL, &error) == FAILURE) { + aws_php_throw_exception("Unable to initialize callback from callable via zend_fcall_info_init: %s", error); + } + + /* Allocate the stack frame of zval arguments and fill them in */ + const size_t num_args = strlen(arg_types); + zval *stack = alloca(sizeof(zval) * num_args); + zval *retval = NULL; + int arg_idx = 0; + va_list va; + va_start(va, arg_types); + while (arg_idx < num_args) { + const char arg_type = arg_types[arg_idx]; + switch (arg_type) { + /* zval types */ + case 'a': + case 'A': + case 'n': + case 'o': + case 'r': + case 'z': { + zval *zval_val = va_arg(va, zval *); + ZVAL_ZVAL(&stack[arg_idx], zval_val, 0, 0); + break; + } + /* buffers/strings (char *, size_t) */ + case 'p': + case 's': { + const char *buf = va_arg(va, const char *); + const size_t len = va_arg(va, size_t); +#if AWS_PHP_AT_LEAST_7 + ZVAL_STRINGL(&stack[arg_idx], buf, len); +#else + ZVAL_STRINGL(&stack[arg_idx], buf, len, 0); +#endif + break; + } + /* other primitives */ + case 'b': { + zend_bool bool_val = va_arg(va, int); + ZVAL_BOOL(&stack[arg_idx], bool_val); + break; + } + case 'd': { + double double_val = va_arg(va, double); + ZVAL_DOUBLE(&stack[arg_idx], double_val); + break; + } + case 'l': { + zend_ulong long_val = va_arg(va, zend_ulong); + ZVAL_LONG(&stack[arg_idx], long_val); + break; + } + /* strings (zend_string), not supported in PHP 5.6, therefore not supported */ + case 'P': + case 'S': + /* unsupported */ + case 'C': + case 'f': + case 'h': + case 'H': + case 'O': + aws_php_throw_exception("Unsupported argument type to aws_php_invoke_callback: %c", arg_type); + break; + default: + aws_php_throw_exception("Unsupported argument type to aws_php_invoke_callback: %c", arg_type); + break; + } + ++arg_idx; + } + va_end(va); + + /* set up the stack for the call */ +#if AWS_PHP_AT_LEAST_7 + zend_fcall_info_argp(&fci, num_args, stack); +#else + /* PHP5.6 may mutate the arguments due to coercion */ + zval **args = alloca(sizeof(zval *) * num_args); + for (int arg_idx = 0; arg_idx < num_args; ++arg_idx) { + args[arg_idx] = &stack[arg_idx]; + } + zend_fcall_info_argp(&fci, num_args, &args); +#endif + + /* PHP5 requires us to have a retval on the stack that zend fills out */ +#if !AWS_PHP_AT_LEAST_7 + fci.retval_ptr_ptr = &retval; +#endif + + if (zend_call_function(&fci, &fcc) == FAILURE) { + aws_php_throw_exception("zend_call_function failed in aws_php_invoke_callback"); + } + + /* PHP7+ allocates its own retval, so we need to copy it out */ +#if AWS_PHP_AT_LEAST_7 + retval = fci.retval; +#endif + + /* Clean up arguments */ + for (int arg_idx = 0; arg_idx < num_args; ++arg_idx) { +#if !AWS_PHP_AT_LEAST_7 + zval_ptr_dtor(args[arg_idx]); +#endif + zval_ptr_dtor(&stack[arg_idx]); + } + + return retval; +} + ZEND_DECLARE_MODULE_GLOBALS(awscrt); PHP_INI_BEGIN() @@ -60,10 +232,7 @@ PHP_FUNCTION(aws_crt_last_error) { /* aws_crt_error_str(int error_code) */ PHP_FUNCTION(aws_crt_error_str) { zend_ulong error_code = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error_code) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &error_code); AWS_RETURN_STRING(aws_crt_error_str(error_code)); } @@ -71,10 +240,7 @@ PHP_FUNCTION(aws_crt_error_str) { /* aws_crt_error_name(int error_code) */ PHP_FUNCTION(aws_crt_error_name) { zend_ulong error_code = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error_code) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &error_code); AWS_RETURN_STRING(aws_crt_error_name(error_code)); } @@ -82,25 +248,20 @@ PHP_FUNCTION(aws_crt_error_name) { /* aws_crt_error_debug_str(int error_code) */ PHP_FUNCTION(aws_crt_error_debug_str) { zend_ulong error_code = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error_code) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &error_code); AWS_RETURN_STRING(aws_crt_error_debug_str(error_code)); } PHP_FUNCTION(aws_crt_event_loop_group_options_new) { + aws_php_parse_parameters_none(); aws_crt_event_loop_group_options *options = aws_crt_event_loop_group_options_new(); RETURN_LONG((zend_ulong)options); } PHP_FUNCTION(aws_crt_event_loop_group_options_release) { zend_ulong php_options = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - return; - } + aws_php_parse_parameters("l", &php_options); aws_crt_event_loop_group_options *options = (void *)php_options; aws_crt_event_loop_group_options_release(options); @@ -109,10 +270,7 @@ PHP_FUNCTION(aws_crt_event_loop_group_options_release) { PHP_FUNCTION(aws_crt_event_loop_group_options_set_max_threads) { zend_ulong php_options = 0; zend_ulong num_threads = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &php_options, &num_threads) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ll", &php_options, &num_threads); aws_crt_event_loop_group_options *options = (void *)php_options; aws_crt_event_loop_group_options_set_max_threads(options, num_threads); @@ -121,9 +279,7 @@ PHP_FUNCTION(aws_crt_event_loop_group_options_set_max_threads) { PHP_FUNCTION(aws_crt_event_loop_group_new) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_options); aws_crt_event_loop_group_options *options = (void *)php_options; aws_crt_event_loop_group *elg = aws_crt_event_loop_group_new(options); @@ -133,9 +289,7 @@ PHP_FUNCTION(aws_crt_event_loop_group_new) { PHP_FUNCTION(aws_crt_event_loop_group_release) { zend_ulong php_elg = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_elg) == FAILURE) { - return; - } + aws_php_parse_parameters("l", &php_elg); struct aws_event_loop_group *elg = (void *)php_elg; aws_crt_event_loop_group_release(elg); @@ -143,7 +297,7 @@ PHP_FUNCTION(aws_crt_event_loop_group_release) { PHP_FUNCTION(aws_crt_input_stream_options_new) { if (zend_parse_parameters_none() == FAILURE) { - RETURN_NULL(); + aws_php_argparse_fail(); } aws_crt_input_stream_options *options = aws_crt_input_stream_options_new(); @@ -153,9 +307,7 @@ PHP_FUNCTION(aws_crt_input_stream_options_new) { PHP_FUNCTION(aws_crt_input_stream_options_release) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - return; - } + aws_php_parse_parameters("l", &php_options); aws_crt_input_stream_options *options = (void *)php_options; aws_crt_input_stream_options_release(options); @@ -170,9 +322,7 @@ PHP_FUNCTION(aws_crt_input_stream_options_set_user_data) { zend_ulong php_options = 0; zval *user_data = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &php_options, &user_data) == FAILURE) { - return; - } + aws_php_parse_parameters("lz", &php_options, &user_data); aws_crt_input_stream_options *options = (void *)php_options; php_stream *stream = NULL; @@ -220,9 +370,7 @@ static void s_php_stream_destroy(void *user_data) { PHP_FUNCTION(aws_crt_input_stream_new) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_options); aws_crt_input_stream_options *options = (void *)php_options; aws_crt_input_stream_options_set_seek(options, s_php_stream_seek); @@ -237,9 +385,7 @@ PHP_FUNCTION(aws_crt_input_stream_new) { PHP_FUNCTION(aws_crt_input_stream_release) { zend_ulong php_stream = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_stream) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_stream); aws_crt_input_stream *stream = (void *)php_stream; aws_crt_input_stream_release(stream); @@ -250,9 +396,7 @@ PHP_FUNCTION(aws_crt_input_stream_seek) { zend_ulong offset = 0; zend_ulong basis = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &php_stream, &offset, &basis) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("lll", &php_stream, &offset, &basis); aws_crt_input_stream *stream = (void *)php_stream; RETURN_LONG(aws_crt_input_stream_seek(stream, offset, basis)); @@ -262,9 +406,7 @@ PHP_FUNCTION(aws_crt_input_stream_read) { zend_ulong php_stream = 0; zend_ulong length = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &php_stream, &length) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ll", &php_stream, &length); aws_crt_input_stream *stream = (void *)php_stream; uint8_t *buf = emalloc(length); @@ -276,9 +418,7 @@ PHP_FUNCTION(aws_crt_input_stream_read) { PHP_FUNCTION(aws_crt_input_stream_eof) { zend_ulong php_stream = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_stream) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_stream); aws_crt_input_stream *stream = (void *)php_stream; aws_crt_input_stream_status status = {0}; @@ -289,9 +429,7 @@ PHP_FUNCTION(aws_crt_input_stream_eof) { PHP_FUNCTION(aws_crt_input_stream_get_length) { zend_ulong php_stream = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_stream) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_stream); aws_crt_input_stream *stream = (void *)php_stream; int64_t length = 0; @@ -303,9 +441,7 @@ PHP_FUNCTION(aws_crt_http_message_new_from_blob) { const char *blob = NULL; size_t blob_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &blob, &blob_len) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("s", &blob, &blob_len); aws_crt_http_message *message = aws_crt_http_message_new_from_blob((uint8_t *)blob, blob_len); RETURN_LONG((zend_ulong)message); @@ -314,9 +450,7 @@ PHP_FUNCTION(aws_crt_http_message_new_from_blob) { PHP_FUNCTION(aws_crt_http_message_to_blob) { zend_ulong php_msg = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_msg) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_msg); aws_crt_http_message *message = (void *)php_msg; uint8_t *blob = NULL; @@ -329,9 +463,7 @@ PHP_FUNCTION(aws_crt_http_message_to_blob) { PHP_FUNCTION(aws_crt_http_message_release) { zend_ulong php_msg = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_msg) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_msg); aws_crt_http_message *message = (void *)php_msg; aws_crt_http_message_release(message); @@ -345,9 +477,7 @@ PHP_FUNCTION(aws_crt_credentials_options_new) { PHP_FUNCTION(aws_crt_credentials_options_release) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_options); aws_crt_credentials_options *options = (void *)php_options; aws_crt_credentials_options_release(options); @@ -358,9 +488,7 @@ PHP_FUNCTION(aws_crt_credentials_options_set_access_key_id) { const char *access_key_id = NULL; size_t access_key_id_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &php_options, &access_key_id, &access_key_id_len) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ls", &php_options, &access_key_id, &access_key_id_len); aws_crt_credentials_options *options = (void *)php_options; aws_crt_credentials_options_set_access_key_id(options, (uint8_t *)access_key_id, access_key_id_len); @@ -385,9 +513,7 @@ PHP_FUNCTION(aws_crt_credentials_options_set_session_token) { const char *session_token = NULL; size_t session_token_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &php_options, &session_token, &session_token_len) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ls", &php_options, &session_token, &session_token_len); aws_crt_credentials_options *options = (void *)php_options; aws_crt_credentials_options_set_session_token(options, (uint8_t *)session_token, session_token_len); @@ -396,9 +522,7 @@ PHP_FUNCTION(aws_crt_credentials_options_set_session_token) { PHP_FUNCTION(aws_crt_credentials_options_set_expiration_timepoint_seconds) { zend_ulong php_options = 0; zend_ulong expiration_timepoint_seconds = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &php_options, &expiration_timepoint_seconds) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ll", &php_options, &expiration_timepoint_seconds); aws_crt_credentials_options *options = (void *)php_options; aws_crt_credentials_options_set_expiration_timepoint_seconds(options, expiration_timepoint_seconds); @@ -407,9 +531,7 @@ PHP_FUNCTION(aws_crt_credentials_options_set_expiration_timepoint_seconds) { PHP_FUNCTION(aws_crt_credentials_new) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_options); aws_crt_credentials_options *options = (void *)php_options; aws_crt_credentials *credentials = aws_crt_credentials_new(options); @@ -419,9 +541,7 @@ PHP_FUNCTION(aws_crt_credentials_new) { PHP_FUNCTION(aws_crt_credentials_release) { zend_ulong php_credentials = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_credentials) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_credentials); aws_crt_credentials *credentials = (void *)php_credentials; aws_crt_credentials_release(credentials); @@ -430,9 +550,7 @@ PHP_FUNCTION(aws_crt_credentials_release) { PHP_FUNCTION(aws_crt_credentials_provider_release) { zend_ulong php_creds_provider = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_creds_provider) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_creds_provider); aws_crt_credentials_provider *provider = (void *)php_creds_provider; aws_crt_credentials_provider_release(provider); @@ -446,9 +564,7 @@ PHP_FUNCTION(aws_crt_credentials_provider_static_options_new) { PHP_FUNCTION(aws_crt_credentials_provider_static_options_release) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_options); aws_crt_credentials_provider_static_options *options = (void *)php_options; aws_crt_credentials_provider_static_options_release(options); @@ -459,9 +575,7 @@ PHP_FUNCTION(aws_crt_credentials_provider_static_options_set_access_key_id) { const char *access_key_id = NULL; size_t access_key_id_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &php_options, &access_key_id, &access_key_id_len) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ls", &php_options, &access_key_id, &access_key_id_len); aws_crt_credentials_provider_static_options *options = (void *)php_options; aws_crt_credentials_provider_static_options_set_access_key_id(options, (uint8_t *)access_key_id, access_key_id_len); @@ -487,9 +601,7 @@ PHP_FUNCTION(aws_crt_credentials_provider_static_options_set_session_token) { const char *session_token = NULL; size_t session_token_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &php_options, &session_token, &session_token_len) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("ls", &php_options, &session_token, &session_token_len); aws_crt_credentials_provider_static_options *options = (void *)php_options; aws_crt_credentials_provider_static_options_set_session_token(options, (uint8_t *)session_token, session_token_len); @@ -498,15 +610,209 @@ PHP_FUNCTION(aws_crt_credentials_provider_static_options_set_session_token) { PHP_FUNCTION(aws_crt_credentials_provider_static_new) { zend_ulong php_options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &php_options) == FAILURE) { - RETURN_NULL(); - } + aws_php_parse_parameters("l", &php_options); aws_crt_credentials_provider_static_options *options = (void *)php_options; aws_crt_credentials_provider *provider = aws_crt_credentials_provider_static_new(options); RETURN_LONG((zend_ulong)provider); } +PHP_FUNCTION(aws_crt_signing_config_aws_new) { + if (zend_parse_parameters_none() == FAILURE) { + RETURN_NULL(); + } + + aws_crt_signing_config_aws *signing_config = aws_crt_signing_config_aws_new(); + RETURN_LONG((zend_ulong)signing_config); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_release) { + zend_ulong php_signing_config = 0; + + aws_php_parse_parameters("l", &php_signing_config); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_release(signing_config); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_algorithm) { + zend_ulong php_signing_config = 0; + zend_ulong php_algorithm = 0; + + aws_php_parse_parameters("ll", &php_signing_config, &php_algorithm); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_algorithm algorithm = php_algorithm; + aws_crt_signing_config_aws_set_algorithm(signing_config, algorithm); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_signature_type) { + zend_ulong php_signing_config = 0; + zend_ulong php_signature_type = 0; + + aws_php_parse_parameters("ll", &php_signing_config, &php_signature_type); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signature_type signature_type = php_signature_type; + aws_crt_signing_config_aws_set_signature_type(signing_config, signature_type); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_credentials_provider) { + zend_ulong php_signing_config = 0; + zend_ulong php_credentials_provider = 0; + + aws_php_parse_parameters("ll", &php_signing_config, &php_credentials_provider); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_credentials_provider *credentials_provider = (void *)php_credentials_provider; + aws_crt_signing_config_aws_set_credentials_provider(signing_config, credentials_provider); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_region) { + zend_ulong php_signing_config = 0; + const char *region = NULL; + size_t region_len = 0; + + aws_php_parse_parameters("ls", &php_signing_config, ®ion, ®ion_len); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_region(signing_config, (uint8_t *)region, region_len); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_service) { + zend_ulong php_signing_config = 0; + const char *service = NULL; + size_t service_len = 0; + + aws_php_parse_parameters("ls", &php_signing_config, &service, &service_len); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_service(signing_config, (uint8_t *)service, service_len); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_use_double_uri_encode) { + zend_ulong php_signing_config = 0; + zend_bool php_use_double_uri_encode = 0; + + aws_php_parse_parameters("lb", &php_signing_config, &php_use_double_uri_encode); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_use_double_uri_encode(signing_config, php_use_double_uri_encode); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_should_normalize_uri_path) { + zend_ulong php_signing_config = 0; + zend_bool php_should_normalize_uri_path = 0; + + aws_php_parse_parameters("lb", &php_signing_config, &php_should_normalize_uri_path); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_should_normalize_uri_path(signing_config, php_should_normalize_uri_path); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_omit_session_token) { + zend_ulong php_signing_config = 0; + zend_bool php_omit_session_token = 0; + + aws_php_parse_parameters("lb", &php_signing_config, &php_omit_session_token); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_omit_session_token(signing_config, php_omit_session_token); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_signed_body_value) { + zend_ulong php_signing_config = 0; + const char *signed_body_value = NULL; + size_t signed_body_value_len = 0; + + aws_php_parse_parameters("ls", &php_signing_config, &signed_body_value, &signed_body_value_len); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_signed_body_value( + signing_config, (uint8_t *)signed_body_value, signed_body_value_len); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_signed_body_header_type) { + zend_ulong php_signing_config = 0; + zend_ulong php_signed_body_header_type = 0; + + aws_php_parse_parameters("ll", &php_signing_config, &php_signed_body_header_type); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signed_body_header_type signed_body_header_type = php_signed_body_header_type; + aws_crt_signing_config_aws_set_signed_body_header_type(signing_config, signed_body_header_type); +} + +PHP_FUNCTION(aws_crt_signing_config_aws_set_expiration_in_seconds) { + zend_ulong php_signing_config = 0; + zend_ulong php_expiration_in_seconds = 0; + + aws_php_parse_parameters("ll", &php_signing_config, &php_expiration_in_seconds); + + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + aws_crt_signing_config_aws_set_expiration_in_seconds(signing_config, php_expiration_in_seconds); +} + +PHP_FUNCTION(aws_crt_signable_new_from_http_request) { + zend_ulong php_http_message = 0; + + aws_php_parse_parameters("l", &php_http_message); + + const aws_crt_http_message *http_message = (void *)php_http_message; + aws_crt_signable *signable = aws_crt_signable_new_from_http_request(http_message); + RETURN_LONG((zend_ulong)signable); +} + +PHP_FUNCTION(aws_crt_signable_new_from_chunk) { + zend_ulong php_input_stream = 0; + const char *previous_signature = NULL; + size_t previous_signature_len = 0; + + aws_php_parse_parameters("ls", &php_input_stream, &previous_signature, &previous_signature_len); + + aws_crt_input_stream *input_stream = (void *)php_input_stream; + aws_crt_signable *signable = + aws_crt_signable_new_from_chunk(input_stream, (uint8_t *)previous_signature, previous_signature_len); + RETURN_LONG((zend_ulong)signable); +} + +PHP_FUNCTION(aws_crt_signable_new_from_canonical_request) { + const char *canonical_request = NULL; + size_t canonical_request_len = 0; + + aws_crt_signable *signable = + aws_crt_signable_new_from_canonical_request((uint8_t *)canonical_request, canonical_request_len); + RETURN_LONG((zend_ulong)signable); +} + +PHP_FUNCTION(aws_crt_signable_release) { + zend_ulong php_signable = 0; + + aws_php_parse_parameters("l", &php_signable); + + aws_crt_signable *signable = (void *)php_signable; + aws_crt_signable_release(signable); +} + +static void s_on_sign_request_aws_complete(aws_crt_signing_result *result, int error_code, void *user_data) { + zval *on_complete = user_data; + + aws_php_invoke_callback(on_complete, "ll", (zend_ulong)result, (zend_ulong)error_code); +} + +PHP_FUNCTION(aws_crt_sign_request_aws) { + zend_ulong php_signable = 0; + zend_ulong php_signing_config = 0; + zval *php_on_complete = 0; + + aws_php_parse_parameters("llz", &php_signable, &php_signing_config, &php_on_complete); + + aws_crt_signable *signable = (void *)php_signable; + aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; + int ret = aws_crt_sign_request_aws(signable, signing_config, s_on_sign_request_aws_complete, php_on_complete); + RETURN_LONG(ret); +} + zend_module_entry awscrt_module_entry = { STANDARD_MODULE_HEADER, "awscrt", diff --git a/src/AWS/CRT/Auth/AwsCredentials.php b/src/AWS/CRT/Auth/AwsCredentials.php index 1e13852..6f6acee 100644 --- a/src/AWS/CRT/Auth/AwsCredentials.php +++ b/src/AWS/CRT/Auth/AwsCredentials.php @@ -20,12 +20,12 @@ use AWS\CRT\Options as Options; final class AwsCredentials extends NativeResource { static function defaults() { - return array( + return [ 'access_key_id' => '', 'secret_access_key' => '', 'session_token' => '', 'expiration_timepoint_seconds' => 0, - ); + ]; } private $access_key_id; @@ -37,16 +37,14 @@ final class AwsCredentials extends NativeResource { return $this->$name; } - function __construct($options = []) { + function __construct(array $options = []) { parent::__construct(); - if (count($options) == 0) { - $options = self::defaults(); - } - $options = new Options($options); - $this->access_key_id = $options->getString('access_key_id'); - $this->secret_access_key = $options->getString('secret_access_key'); - $this->session_token = $options->getString('session_token'); - $this->expiration_timepoint_seconds = $options->getInt('expiration_timepoint_seconds'); + + $options = new Options($options, self::defaults()); + $this->access_key_id = $options->access_key_id->asString(); + $this->secret_access_key = $options->secret_access_key->asString(); + $this->session_token = $options->session_token ? $options->session_token->asString() : null; + $this->expiration_timepoint_seconds = $options->expiration_timepoint_seconds->asInt(); if (strlen($this->access_key_id) == 0) { throw new \InvalidArgumentException("access_key_id must be provided"); diff --git a/src/AWS/CRT/Auth/Signable.php b/src/AWS/CRT/Auth/Signable.php new file mode 100644 index 0000000..100b56a --- /dev/null +++ b/src/AWS/CRT/Auth/Signable.php @@ -0,0 +1,43 @@ +signable_new_from_http_request($http_message->native); + }); + } + + public static function fromChunk($chunk_stream, $previous_signature="") { + if (!($chunk_stream instanceof InputStream)) { + $chunk_stream = new InputStream($chunk_stream); + } + return new Signable(function() use($chunk_stream, $previous_signature) { + return self::$crt->signable_new_from_chunk($chunk_stream->native, $previous_signature); + }); + } + + public static function fromCanonicalRequest($canonical_request) { + return new Signable(function() use($canonical_request) { + return self::$crt->signable_new_from_canonical_request($canonical_request); + }); + } + + protected function __construct($ctor) { + parent::__construct(); + $this->acquire($ctor()); + } + + function __destruct() { + self::$crt->signable_release($this->release()); + parent::__destruct(); + } +} \ No newline at end of file diff --git a/src/AWS/CRT/Auth/SignatureType.php b/src/AWS/CRT/Auth/SignatureType.php new file mode 100644 index 0000000..3d3b99f --- /dev/null +++ b/src/AWS/CRT/Auth/SignatureType.php @@ -0,0 +1,15 @@ +sign_request_aws($signable, $signing_config, $on_complete); + } +} \ No newline at end of file diff --git a/src/AWS/CRT/Auth/SigningAlgorithm.php b/src/AWS/CRT/Auth/SigningAlgorithm.php new file mode 100644 index 0000000..4d3358d --- /dev/null +++ b/src/AWS/CRT/Auth/SigningAlgorithm.php @@ -0,0 +1,10 @@ + SigningAlgorithm::SIGv4, + 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, + 'credentials_provider' => null, + 'region' => null, + 'service' => null, + 'use_double_uri_encode' => false, + 'should_normalize_uri_path' => false, + 'omit_session_token' => false, + 'signed_body_value' => null, + 'signed_body_header_type' => SignedBodyHeaderType::NONE, + 'expiration_in_seconds' => 0, + ]; + } + + private $options; + + public function __construct(array $options = []) { + parent::__construct(); + $this->options = $options = new Options($options, self::defaults()); + $sc = $this->acquire(self::$crt->signing_config_aws_new()); + self::$crt->signing_config_aws_set_algorithm($sc, $options->algorithm->asInt()); + self::$crt->signing_config_aws_set_signature_type($sc, $options->signature_type->asInt()); + self::$crt->signing_config_aws_set_credentials_provider($sc, $options->credentials_provider->asObject()); + self::$crt->signing_config_aws_set_region($sc, $options->region->asString()); + self::$crt->signing_config_aws_set_service($sc, $options->service->asString()); + self::$crt->signing_config_aws_set_use_double_uri_encode($sc, $options->use_double_uri_encode->asBool()); + self::$crt->signing_config_aws_set_should_normalize_uri_path($sc, $options->should_normalize_uri_path->asBool()); + self::$crt->signing_config_aws_set_omit_session_token($sc, $options->omit_session_token->asBool()); + self::$crt->signing_config_aws_set_signed_body_value($sc, $options->signed_body_value->asString()); + self::$crt->signing_config_aws_set_signed_body_header_type($sc, $options->signed_body_header_type->asInt()); + self::$crt->signing_config_aws_set_expiration_in_seconds($sc, $options->expiration_in_seconds->asInt()); + } + + function __destruct() + { + self::$crt->signing_config_aws_release($this->release()); + parent::__destruct(); + } + + public function __get($name) { + return $this->options->get($name); + } +} \ No newline at end of file diff --git a/src/AWS/CRT/Auth/StaticCredentialsProvider.php b/src/AWS/CRT/Auth/StaticCredentialsProvider.php index 3467e9b..8dc6249 100644 --- a/src/AWS/CRT/Auth/StaticCredentialsProvider.php +++ b/src/AWS/CRT/Auth/StaticCredentialsProvider.php @@ -15,15 +15,7 @@ namespace AWS\CRT\Auth; */ final class StaticCredentialsProvider extends CredentialsProvider { - static function defaults() { - return array( - 'access_key_id' => '', - 'secret_access_key' => '', - 'session_token' => '', - ); - } - - private $credentials = null; + private $credentials; public function __get($name) { return $this->$name; @@ -31,9 +23,6 @@ final class StaticCredentialsProvider extends CredentialsProvider { function __construct(array $options = []) { parent::__construct(); - if (count($options) == 0) { - $options = self::defaults(); - } $this->credentials = new AwsCredentials($options); $provider_options = self::$crt->credentials_provider_static_options_new(); diff --git a/src/AWS/CRT/CRT.php b/src/AWS/CRT/CRT.php index 5fd2124..aa40a06 100644 --- a/src/AWS/CRT/CRT.php +++ b/src/AWS/CRT/CRT.php @@ -214,4 +214,76 @@ final class CRT { function http_message_release($message) { self::$impl->aws_crt_http_message_release($message); } + + function signing_config_aws_new() { + return self::$impl->aws_crt_signing_config_aws_new(); + } + + function signing_config_aws_release($signing_config) { + return self::$impl->aws_crt_signing_config_aws_release($signing_config); + } + + function signing_config_aws_set_algorithm($signing_config, $algorithm) { + self::$impl->aws_crt_signing_config_aws_set_algorithm($signing_config, (int)$algorithm); + } + + function signing_config_aws_set_signature_type($signing_config, $signature_type) { + self::$impl->aws_crt_signing_config_aws_set_signature_type($signing_config, (int)$signature_type); + } + + function signing_config_aws_set_credentials_provider($signing_config, $credentials_provider) { + self::$impl->aws_crt_signing_config_aws_set_credentials_provider($signing_config, $credentials_provider); + } + + function signing_config_aws_set_region($signing_config, $region) { + self::$impl->aws_crt_signing_config_aws_set_region($signing_config, $region); + } + + function signing_config_aws_set_service($signing_config, $service) { + self::$impl->aws_crt_signing_config_aws_set_service($signing_config, $service); + } + + function signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode) { + self::$impl->aws_crt_signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode); + } + + function signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path) { + self::$impl->aws_crt_signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path); + } + + function signing_config_aws_set_omit_session_token($signing_config, $omit_session_token) { + self::$impl->aws_crt_signing_config_aws_set_omit_session_token($signing_config, $omit_session_token); + } + + function signing_config_aws_set_signed_body_value($signing_config, $signed_body_value) { + self::$impl->aws_crt_signing_config_aws_set_signed_body_value($signing_config, $signed_body_value); + } + + function signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type) { + self::$impl->aws_crt_signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type); + } + + function signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds) { + self::$impl->aws_crt_signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds); + } + + function signable_new_from_http_request($http_message) { + return self::$impl->aws_crt_signable_new_from_http_request($http_message); + } + + function signable_new_from_chunk($chunk_stream, $previous_signature) { + return self::$impl->aws_crt_signable_new_from_chunk($chunk_stream, $previous_signature); + } + + function signable_new_from_canonical_request($canonical_request) { + return self::$impl->aws_crt_signable_new_from_canonical_request($canonical_request); + } + + function signable_release($signable) { + self::$impl->aws_crt_signable_release($signable); + } + + function sign_request_aws($signable, $signing_config, $on_complete) { + return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete); + } } diff --git a/src/AWS/CRT/IO/EventLoopGroup.php b/src/AWS/CRT/IO/EventLoopGroup.php index b1c297b..7e989e7 100644 --- a/src/AWS/CRT/IO/EventLoopGroup.php +++ b/src/AWS/CRT/IO/EventLoopGroup.php @@ -18,17 +18,14 @@ use AWS\CRT\Options as Options; final class EventLoopGroup extends NativeResource { static function defaults() { - return array( + return [ 'max_threads' => 0, - ); + ]; } function __construct(array $options = []) { parent::__construct(); - if (count($options) == 0) { - $options = self::defaults(); - } - $options = new Options($options); + $options = new Options($options, self::defaults()); $elg_options = self::$crt->event_loop_group_options_new(); self::$crt->event_loop_group_options_set_max_threads($elg_options, $options->getInt('max_threads')); $this->acquire(self::$crt->event_loop_group_new($elg_options)); diff --git a/src/AWS/CRT/NativeResource.php b/src/AWS/CRT/NativeResource.php index f1f8815..528df75 100644 --- a/src/AWS/CRT/NativeResource.php +++ b/src/AWS/CRT/NativeResource.php @@ -16,7 +16,7 @@ abstract class NativeResource { protected static $resources = []; protected $native = null; - function __construct() { + protected function __construct() { if (is_null(self::$crt)) { self::$crt = new CRT(); } @@ -25,7 +25,7 @@ abstract class NativeResource { } protected function acquire($handle) { - $this->native = $handle; + return $this->native = $handle; } protected function release() { diff --git a/src/AWS/CRT/Options.php b/src/AWS/CRT/Options.php index dcb7776..f362cc5 100644 --- a/src/AWS/CRT/Options.php +++ b/src/AWS/CRT/Options.php @@ -5,15 +5,46 @@ */ namespace AWS\CRT; -final class Options { - private $options = []; +final class OptionValue { + private $value; + function __construct($value) { + $this->value = $value; + } - public function __construct($opts = []) { - $this->options = $opts; + public function asObject() { + return $this->value; + } + + public function asMixed() { + return $this->value; + } + + public function asInt() { + return empty($this->value) ? 0 : (int)$this->value; + } + + public function asBool() { + return boolval($this->value); + } + + public function asString() { + return !empty($this->value) ? strval($this->value) : ""; + } + + public function asArray() { + return is_array($this->value) ? $this->value : (!empty($this->value) ? [$this->value] : []); + } +} + +final class Options { + private $options; + + public function __construct($opts = [], $defaults = []) { + $this->options = array_replace($defaults, empty($opts) ? [] : $opts); } public function __get($name) { - return (isset($this->options[$name])) ? $this->options[$name] : null; + return $this->get($name); } public function asArray() { @@ -24,12 +55,19 @@ final class Options { return array_merge_recursive([], $this->options); } + public function get($name) { + return new OptionValue($this->options[$name]); + } + public function getInt($name) { - $val = $this->$name; - return (is_null($val)) ? 0 : (int)$val; + return $this->get($name)->asInt(); } public function getString($name) { - return !empty($this->options[$name]) ? strval($this->options[$name]) : ""; + return $this->get($name)->asString(); + } + + public function getBool($name) { + return $this->get($name)->asBool(); } } diff --git a/tests/SigningTest.php b/tests/SigningTest.php new file mode 100644 index 0000000..4194b09 --- /dev/null +++ b/tests/SigningTest.php @@ -0,0 +1,87 @@ +assertNotNull($config, "Failed to create default SigningConfigAWS"); + $config = null; + } + + public function testConfigAWSConstructionWithOptions() { + $options = SigningConfigAWS::defaults(); + $options['service'] = 'CRT'; + $options['region'] = 'CRT'; + $config = new SigningConfigAWS($options); + $this->assertNotNull($config, "Failed to create SigningConfigAWS with custom options"); + $config = null; + } + + public function testSignableFromHttpRequestLifetime() { + $request = new Request('GET', '/'); + $signable = Signable::fromHttpRequest($request); + $this->assertNotNull($signable, "Failed to create Signable from HTTP::Request"); + $signable = null; + } + + public function testSignableFromChunkLifetime() { + $chunk = "THIS IS A TEST CHUNK IT CONTAINS MULTITUDES"; + $stream = fopen("php://memory", 'r+'); + fputs($stream, $chunk); + rewind($stream); + $signable = Signable::fromChunk($stream); + $this->assertNotNull($signable, "Failed to create Signable from chunk stream"); + $signable = null; + } + + public function testSignableFromCanonicalRequestLifetime() { + $canonical_request = "THIS IS A CANONICAL_REQUEST. IT IS DEEPLY CANONICAL"; + $signable = Signable::fromCanonicalRequest($canonical_request); + $this->assertNotNull($signable, "Failed to create Signable from canonical request"); + $signable = null; + } + + const SIGV4TEST_ACCESS_KEY_ID = 'AKIDEXAMPLE'; + const SIGV4TEST_SECRET_ACCESS_KEY = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'; + const SIGV4TEST_SESSION_TOKEN = null; + const SIGV4TEST_SERVICE = 'service'; + const SIGV4TEST_REGION = 'us-east-1'; + public function testSigv4HeaderSigning() { + $this->markTestSkipped('WIP'); + $date = mktime(12, 36, 0, 8, 30, 2015); + $credentials_provider = new StaticCredentialsProvider([ + 'access_key_id' => self::SIGV4TEST_ACCESS_KEY_ID, + 'secret_access_key' => self::SIGV4TEST_SECRET_ACCESS_KEY, + 'session_token' => self::SIGV4TEST_SESSION_TOKEN, + ]); + $signing_config = new SigningConfigAWS([ + 'algorithm' => SigningAlgorithm::SIGv4, + 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, + 'credentials_provider' => $credentials_provider, + 'region' => self::SIGV4TEST_REGION, + 'service' => self::SIGV4TEST_SERVICE, + ]); + $http_request = new Request('GET', '/', [], ['Host' => 'example.amazonaws.com']); + $this->assertNotNull($http_request, "Unable to create HttpRequest for signing"); + $signable = Signable::fromHttpRequest($http_request); + $this->assertNotNull($signable, "Unable to create signable from HttpRequest"); + + Signing::signRequestAws($signable, $signing_config, function() { + + }); + } +}