diff --git a/Makefile b/Makefile index 1fc78b6ab64fb213762a0c345b7bdaf95ea6c2ee..08f5ba2672109bd7737e677dad2086018357a251 100644 --- a/Makefile +++ b/Makefile @@ -234,6 +234,7 @@ OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/ope ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/zlib.c -lz $(LDFLAGS) PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/perftools.c -lprofiler $(LDFLAGS) PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o /dev/null test/build/protobuf.cc -lprotobuf $(LDFLAGS) +PROTOC_CMD = which protoc PROTOC_CHECK_CMD = protoc --version | grep -q libprotoc.3 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) @@ -244,10 +245,11 @@ LIBS += profiler endif endif +HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false) ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false) -HAS_SYSTEM_PROTOBUF = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false) +HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY) else # override system libraries if the config requires a custom compiled library HAS_SYSTEM_OPENSSL_ALPN = false @@ -255,7 +257,12 @@ HAS_SYSTEM_ZLIB = false HAS_SYSTEM_PROTOBUF = false endif +HAS_PROTOC = $(shell $(PROTOC_CMD) && echo true || echo false) +ifeq ($(HAS_PROTOC),true) HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +else +HAS_VALID_PROTOC = false +endif ifeq ($(wildcard third_party/openssl/ssl/ssl.h),) HAS_EMBEDDED_OPENSSL_ALPN = false @@ -308,8 +315,8 @@ LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE)) ifeq ($(HAS_SYSTEM_PROTOBUF),false) ifeq ($(HAS_EMBEDDED_PROTOBUF),true) PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a -CPPFLAGS += -Ithird_party/protobuf/src -LDFLAGS += -L$(LIBDIR)/$(CONFIG)/protobuf +CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS) +LDFLAGS := -L$(LIBDIR)/$(CONFIG)/protobuf $(LDFLAGS) PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc else NO_PROTOBUF = true @@ -327,6 +334,13 @@ ifeq ($(MAKECMDGOALS),clean) NO_DEPS = true endif +INSTALL_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_SYSTEM_PROTOBUF_VERIFY),true) +INSTALL_OK = true +endif +endif + .SECONDARY = %.pb.h %.pb.cc PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin @@ -463,6 +477,7 @@ grpc_byte_buffer_reader_test: $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test grpc_channel_stack_test: $(BINDIR)/$(CONFIG)/grpc_channel_stack_test grpc_completion_queue_benchmark: $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark grpc_completion_queue_test: $(BINDIR)/$(CONFIG)/grpc_completion_queue_test +grpc_create_jwt: $(BINDIR)/$(CONFIG)/grpc_create_jwt grpc_credentials_test: $(BINDIR)/$(CONFIG)/grpc_credentials_test grpc_fetch_oauth2: $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 grpc_json_token_test: $(BINDIR)/$(CONFIG)/grpc_json_token_test @@ -880,7 +895,7 @@ third_party/protobuf/configure: $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure $(E) "[MAKE] Building protobuf" - $(Q)(cd third_party/protobuf ; CC="$(CC)" CPPFLAGS="-fPIC" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="$(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static) + $(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="-fPIC $(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static) $(Q)$(MAKE) -C third_party/protobuf clean $(Q)$(MAKE) -C third_party/protobuf $(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf @@ -1748,7 +1763,7 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 ) -tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 +tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_create_jwt $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 buildbenchmarks: privatelibs $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark @@ -1915,7 +1930,7 @@ $(OBJDIR)/$(CONFIG)/%.o : %.cc $(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $< -install: install_c install_cxx install-plugins +install: install_c install_cxx install-plugins verify-install install_c: install-headers_c install-static_c install-shared_c @@ -2059,6 +2074,25 @@ else $(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin endif +verify-install: +ifeq ($(SYSTEM_OK),true) + @echo "Your system looks ready to go." + @echo +else + @echo "Your system doesn't have protoc 3.0.0+ installed. While this" + @echo "won't prevent grpc from working, you won't be able to compile" + @echo "and run any meaningful code with it." + @echo + @echo + @echo "Please download and install protobuf 3.0.0+ from:" + @echo + @echo " https://github.com/google/protobuf/releases" + @echo + @echo "Once you've done so, you can re-run this check by doing:" + @echo + @echo " make verify-install" +endif + clean: $(E) "[CLEAN] Cleaning build directories." $(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) @@ -2290,7 +2324,8 @@ LIBGRPC_SRC = \ src/core/iomgr/pollset_multipoller_with_poll_posix.c \ src/core/iomgr/pollset_posix.c \ src/core/iomgr/pollset_windows.c \ - src/core/iomgr/resolve_address.c \ + src/core/iomgr/resolve_address_posix.c \ + src/core/iomgr/resolve_address_windows.c \ src/core/iomgr/sockaddr_utils.c \ src/core/iomgr/socket_utils_common_posix.c \ src/core/iomgr/socket_utils_linux.c \ @@ -2430,7 +2465,8 @@ src/core/iomgr/pollset_multipoller_with_epoll.c: $(OPENSSL_DEP) src/core/iomgr/pollset_multipoller_with_poll_posix.c: $(OPENSSL_DEP) src/core/iomgr/pollset_posix.c: $(OPENSSL_DEP) src/core/iomgr/pollset_windows.c: $(OPENSSL_DEP) -src/core/iomgr/resolve_address.c: $(OPENSSL_DEP) +src/core/iomgr/resolve_address_posix.c: $(OPENSSL_DEP) +src/core/iomgr/resolve_address_windows.c: $(OPENSSL_DEP) src/core/iomgr/sockaddr_utils.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_common_posix.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_linux.c: $(OPENSSL_DEP) @@ -2587,7 +2623,8 @@ $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_epoll.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o: -$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address.o: +$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_posix.o: +$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_windows.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/sockaddr_utils.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_linux.o: @@ -2759,7 +2796,8 @@ LIBGRPC_UNSECURE_SRC = \ src/core/iomgr/pollset_multipoller_with_poll_posix.c \ src/core/iomgr/pollset_posix.c \ src/core/iomgr/pollset_windows.c \ - src/core/iomgr/resolve_address.c \ + src/core/iomgr/resolve_address_posix.c \ + src/core/iomgr/resolve_address_windows.c \ src/core/iomgr/sockaddr_utils.c \ src/core/iomgr/socket_utils_common_posix.c \ src/core/iomgr/socket_utils_linux.c \ @@ -2894,7 +2932,8 @@ $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_epoll.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o: -$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address.o: +$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_posix.o: +$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_windows.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/sockaddr_utils.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_linux.o: @@ -6383,6 +6422,37 @@ endif endif +GRPC_CREATE_JWT_SRC = \ + test/core/security/create_jwt.c \ + +GRPC_CREATE_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CREATE_JWT_SRC)))) + +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL with ALPN. + +$(BINDIR)/$(CONFIG)/grpc_create_jwt: openssl_dep_error + +else + +$(BINDIR)/$(CONFIG)/grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(GRPC_CREATE_JWT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/grpc_create_jwt + +endif + +$(OBJDIR)/$(CONFIG)/test/core/security/create_jwt.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GRPC_CREATE_JWT_OBJS:.o=.dep) +endif +endif + + GRPC_CREDENTIALS_TEST_SRC = \ test/core/security/credentials_test.c \ diff --git a/build.json b/build.json index 002cabe2bc859e4f4cf87da7b7a319fd6aae4bb0..f8c97e3437d2b3b87dc1e743409a5f90451f4d67 100644 --- a/build.json +++ b/build.json @@ -136,7 +136,8 @@ "src/core/iomgr/pollset_multipoller_with_poll_posix.c", "src/core/iomgr/pollset_posix.c", "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address.c", + "src/core/iomgr/resolve_address_posix.c", + "src/core/iomgr/resolve_address_windows.c", "src/core/iomgr/sockaddr_utils.c", "src/core/iomgr/socket_utils_common_posix.c", "src/core/iomgr/socket_utils_linux.c", @@ -1129,6 +1130,20 @@ "gpr" ] }, + { + "name": "grpc_create_jwt", + "build": "tool", + "language": "c", + "src": [ + "test/core/security/create_jwt.c" + ], + "deps": [ + "grpc_test_util", + "grpc", + "gpr_test_util", + "gpr" + ] + }, { "name": "grpc_credentials_test", "build": "test", diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index f03ac8004dad373438e4accd21aae7a8bb0f1710..472887f7c6b4a05dcb8edf14941d4632bd4f454e 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -100,6 +100,14 @@ extern const gpr_timespec grpc_max_auth_token_lifetime; grpc_credentials *grpc_service_account_credentials_create( const char *json_key, const char *scope, gpr_timespec token_lifetime); +/* Creates a JWT credentials object. May return NULL if the input is invalid. + - json_key is the JSON key string containing the client's private key. + - token_lifetime is the lifetime of each Json Web Token (JWT) created with + this credentials. It should not exceed grpc_max_auth_token_lifetime or + will be cropped to this value. */ +grpc_credentials *grpc_jwt_credentials_create(const char *json_key, + gpr_timespec token_lifetime); + /* Creates a fake transport security credentials object for testing. */ grpc_credentials *grpc_fake_transport_security_credentials_create(void); diff --git a/include/grpc/support/host_port.h b/include/grpc/support/host_port.h index 362046cb95d266a4f2ff2121d2c25cb182685d08..2dac38a157c6a8011bac7a139ef353c2e9848cbb 100644 --- a/include/grpc/support/host_port.h +++ b/include/grpc/support/host_port.h @@ -50,6 +50,11 @@ extern "C" { In the unlikely event of an error, returns -1 and sets *out to NULL. */ int gpr_join_host_port(char **out, const char *host, int port); +/* Given a name in the form "host:port" or "[ho:st]:port", split into hostname + and port number, into newly allocated strings, which must later be + destroyed using gpr_free(). */ +void gpr_split_host_port(const char *name, char **host, char **port); + #ifdef __cplusplus } #endif diff --git a/src/core/debug/trace.c b/src/core/debug/trace.c index cdbe168fc85b09961355a69439a362a8041320ad..92acbe924dbe7cb67ebebd02ea32575b7050b89a 100644 --- a/src/core/debug/trace.c +++ b/src/core/debug/trace.c @@ -40,7 +40,7 @@ #include "src/core/support/env.h" #if GRPC_ENABLE_TRACING -gpr_uint32 grpc_trace_bits; +gpr_uint32 grpc_trace_bits = 0; static void add(const char *beg, const char *end, char ***ss, size_t *ns) { size_t n = *ns; diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c index fbacad1e99813bcfa7d6100f39e9f90755e42f54..7570ff18c59d0822b1ba76cebb8cdb330a186336 100644 --- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c +++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c @@ -183,10 +183,10 @@ static int multipoll_with_poll_pollset_maybe_work( grpc_pollset_kick_consume(&pollset->kick_state); } for (i = 1; i < np; i++) { - if (h->pfds[i].revents & POLLIN) { + if (h->pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) { grpc_fd_become_readable(h->watchers[i].fd, allow_synchronous_callback); } - if (h->pfds[i].revents & POLLOUT) { + if (h->pfds[i].revents & (POLLOUT | POLLHUP | POLLERR)) { grpc_fd_become_writable(h->watchers[i].fd, allow_synchronous_callback); } } diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c index 05b78adeb61dc9c13d1ca00a622e43f5ab8dbc2f..87e7aa85ee847688e4488b6ba2993965417d7ec5 100644 --- a/src/core/iomgr/pollset_posix.c +++ b/src/core/iomgr/pollset_posix.c @@ -63,9 +63,9 @@ static void backup_poller(void *p) { gpr_mu_lock(&g_backup_pollset.mu); while (g_shutdown_backup_poller == 0) { gpr_timespec next_poll = gpr_time_add(last_poll, delta); - grpc_pollset_work(&g_backup_pollset, next_poll); + grpc_pollset_work(&g_backup_pollset, gpr_time_add(gpr_now(), gpr_time_from_seconds(1))); gpr_mu_unlock(&g_backup_pollset.mu); - gpr_sleep_until(next_poll); + /*gpr_sleep_until(next_poll);*/ gpr_mu_lock(&g_backup_pollset.mu); last_poll = next_poll; } @@ -277,10 +277,10 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset, if (pfd[0].revents & POLLIN) { grpc_pollset_kick_consume(&pollset->kick_state); } - if (pfd[1].revents & POLLIN) { + if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) { grpc_fd_become_readable(fd, allow_synchronous_callback); } - if (pfd[1].revents & POLLOUT) { + if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) { grpc_fd_become_writable(fd, allow_synchronous_callback); } } diff --git a/src/core/iomgr/resolve_address.c b/src/core/iomgr/resolve_address_posix.c similarity index 78% rename from src/core/iomgr/resolve_address.c rename to src/core/iomgr/resolve_address_posix.c index 6d748c86981421c314a9f8007e3fece91be5fae4..edf40b5ad148eda52ce05b51a9b64aa505a762c8 100644 --- a/src/core/iomgr/resolve_address.c +++ b/src/core/iomgr/resolve_address_posix.c @@ -31,9 +31,8 @@ * */ -#ifndef _POSIX_SOURCE -#define _POSIX_SOURCE -#endif +#include <grpc/support/port_platform.h> +#ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/resolve_address.h" @@ -46,6 +45,7 @@ #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/support/string.h" #include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> #include <grpc/support/log.h> #include <grpc/support/thd.h> #include <grpc/support/time.h> @@ -57,63 +57,6 @@ typedef struct { void *arg; } request; -static void split_host_port(const char *name, char **host, char **port) { - const char *host_start; - size_t host_len; - const char *port_start; - - *host = NULL; - *port = NULL; - - if (name[0] == '[') { - /* Parse a bracketed host, typically an IPv6 literal. */ - const char *rbracket = strchr(name, ']'); - if (rbracket == NULL) { - /* Unmatched [ */ - return; - } - if (rbracket[1] == '\0') { - /* ]<end> */ - port_start = NULL; - } else if (rbracket[1] == ':') { - /* ]:<port?> */ - port_start = rbracket + 2; - } else { - /* ]<invalid> */ - return; - } - host_start = name + 1; - host_len = rbracket - host_start; - if (memchr(host_start, ':', host_len) == NULL) { - /* Require all bracketed hosts to contain a colon, because a hostname or - IPv4 address should never use brackets. */ - return; - } - } else { - const char *colon = strchr(name, ':'); - if (colon != NULL && strchr(colon + 1, ':') == NULL) { - /* Exactly 1 colon. Split into host:port. */ - host_start = name; - host_len = colon - name; - port_start = colon + 1; - } else { - /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ - host_start = name; - host_len = strlen(name); - port_start = NULL; - } - } - - /* Allocate return values. */ - *host = gpr_malloc(host_len + 1); - memcpy(*host, host_start, host_len); - (*host)[host_len] = '\0'; - - if (port_start != NULL) { - *port = gpr_strdup(port_start); - } -} - grpc_resolved_addresses *grpc_blocking_resolve_address( const char *name, const char *default_port) { struct addrinfo hints; @@ -134,12 +77,12 @@ grpc_resolved_addresses *grpc_blocking_resolve_address( un = (struct sockaddr_un *)addrs->addrs->addr; un->sun_family = AF_UNIX; strcpy(un->sun_path, name + 5); - addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family); + addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; return addrs; } /* parse name, splitting it into host and port parts */ - split_host_port(name, &host, &port); + gpr_split_host_port(name, &host, &port); if (host == NULL) { gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); goto done; @@ -233,3 +176,5 @@ void grpc_resolve_address(const char *name, const char *default_port, r->arg = arg; gpr_thd_new(&id, do_request, r, NULL); } + +#endif diff --git a/src/core/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c new file mode 100644 index 0000000000000000000000000000000000000000..877b3f35ed879d259c3e31b835a95a99a75d880b --- /dev/null +++ b/src/core/iomgr/resolve_address_windows.c @@ -0,0 +1,166 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/port_platform.h> +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr.h" +#include "src/core/iomgr/resolve_address.h" + +#include <sys/types.h> +#include <string.h> + +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/support/string.h" +#include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> +#include <grpc/support/log.h> +#include <grpc/support/thd.h> +#include <grpc/support/time.h> + +typedef struct { + char *name; + char *default_port; + grpc_resolve_cb cb; + void *arg; +} request; + +grpc_resolved_addresses *grpc_blocking_resolve_address( + const char *name, const char *default_port) { + struct addrinfo hints; + struct addrinfo *result = NULL, *resp; + char *host; + char *port; + int s; + size_t i; + grpc_resolved_addresses *addrs = NULL; + const gpr_timespec start_time = gpr_now(); + + /* parse name, splitting it into host and port parts */ + gpr_split_host_port(name, &host, &port); + if (host == NULL) { + gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); + goto done; + } + if (port == NULL) { + if (default_port == NULL) { + gpr_log(GPR_ERROR, "no port in name '%s'", name); + goto done; + } + port = gpr_strdup(default_port); + } + + /* Call getaddrinfo */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ + hints.ai_socktype = SOCK_STREAM; /* stream socket */ + hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ + + s = getaddrinfo(host, port, &hints, &result); + if (s != 0) { + gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); + goto done; + } + + /* Success path: set addrs non-NULL, fill it in */ + addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + addrs->naddrs = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + addrs->naddrs++; + } + addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); + i = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); + addrs->addrs[i].len = resp->ai_addrlen; + i++; + } + + /* Temporary logging, to help identify flakiness in dualstack_socket_test. */ + { + const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time); + const int delay_ms = + delay.tv_sec * GPR_MS_PER_SEC + delay.tv_nsec / GPR_NS_PER_MS; + gpr_log(GPR_INFO, "logspam: getaddrinfo(%s, %s) resolved %d addrs in %dms:", + host, port, addrs->naddrs, delay_ms); + for (i = 0; i < addrs->naddrs; i++) { + char *buf; + grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, + 0); + gpr_log(GPR_INFO, "logspam: [%d] %s", i, buf); + gpr_free(buf); + } + } + +done: + gpr_free(host); + gpr_free(port); + if (result) { + freeaddrinfo(result); + } + return addrs; +} + +/* Thread function to asynch-ify grpc_blocking_resolve_address */ +static void do_request(void *rp) { + request *r = rp; + grpc_resolved_addresses *resolved = + grpc_blocking_resolve_address(r->name, r->default_port); + void *arg = r->arg; + grpc_resolve_cb cb = r->cb; + gpr_free(r->name); + gpr_free(r->default_port); + gpr_free(r); + cb(arg, resolved); + grpc_iomgr_unref(); +} + +void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { + gpr_free(addrs->addrs); + gpr_free(addrs); +} + +void grpc_resolve_address(const char *name, const char *default_port, + grpc_resolve_cb cb, void *arg) { + request *r = gpr_malloc(sizeof(request)); + gpr_thd_id id; + grpc_iomgr_ref(); + r->name = gpr_strdup(name); + r->default_port = gpr_strdup(default_port); + r->cb = cb; + r->arg = arg; + gpr_thd_new(&id, do_request, r, NULL); +} + +#endif diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c index 2bd93c6af2c60ea23470dc31b7d8c26f581912a1..181d89cb6d3c019bb1847df367a2b286c7f1a462 100644 --- a/src/core/iomgr/tcp_client_windows.c +++ b/src/core/iomgr/tcp_client_windows.c @@ -43,12 +43,13 @@ #include <grpc/support/slice_buffer.h> #include <grpc/support/useful.h> +#include "src/core/iomgr/alarm.h" +#include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_windows.h" -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/alarm.h" #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_windows.h" typedef struct { void(*cb)(void *arg, grpc_endpoint *tcp); diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index c6864efdc53682e815f71765eee5296972c4d62f..59319da26d118c48939ef61c918238055ddafd7a 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -355,8 +355,9 @@ SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) { return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET; } -void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset *pollset, - grpc_tcp_server_cb cb, void *cb_arg) { +void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset, + size_t pollset_count, grpc_tcp_server_cb cb, + void *cb_arg) { size_t i; GPR_ASSERT(cb); gpr_mu_lock(&s->mu); diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 58679a87aa5509b653f08d4503fd37d34e7a7d97..92878e3b7e3ce5c8a91954acf1d1b239eed1cd04 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -48,6 +48,7 @@ typedef struct { grpc_credentials *creds; grpc_mdstr *host; + grpc_mdstr *method; grpc_call_op op; } call_data; @@ -56,6 +57,7 @@ typedef struct { grpc_channel_security_context *security_context; grpc_mdctx *md_ctx; grpc_mdstr *authority_string; + grpc_mdstr *path_string; grpc_mdstr *error_msg_key; } channel_data; @@ -89,6 +91,26 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, grpc_call_next_op(elem, &((call_data *)elem->call_data)->op); } +static char *build_service_url(const char *url_scheme, call_data *calld) { + char *service_url; + char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); + char *last_slash = strrchr(service, '/'); + if (last_slash == NULL) { + gpr_log(GPR_ERROR, "No '/' found in fully qualified method name"); + service[0] = '\0'; + } else if (last_slash == service) { + /* No service part in fully qualified method name: will just be "/". */ + service[1] = '\0'; + } else { + *last_slash = '\0'; + } + if (url_scheme == NULL) url_scheme = ""; + gpr_asprintf(&service_url, "%s://%s%s", url_scheme, + grpc_mdstr_as_c_string(calld->host), service); + gpr_free(service); + return service_url; +} + static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; @@ -106,9 +128,12 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { } if (channel_creds != NULL && grpc_credentials_has_request_metadata(channel_creds)) { + char *service_url = + build_service_url(channeld->security_context->base.url_scheme, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ - grpc_credentials_get_request_metadata(channel_creds, + grpc_credentials_get_request_metadata(channel_creds, service_url, on_credentials_metadata, elem); + gpr_free(service_url); } else { grpc_call_next_op(elem, op); } @@ -146,6 +171,9 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, if (op->data.metadata->key == channeld->authority_string) { if (calld->host != NULL) grpc_mdstr_unref(calld->host); calld->host = grpc_mdstr_ref(op->data.metadata->value); + } else if (op->data.metadata->key == channeld->path_string) { + if (calld->method != NULL) grpc_mdstr_unref(calld->method); + calld->method = grpc_mdstr_ref(op->data.metadata->value); } grpc_call_next_op(elem, op); break; @@ -194,6 +222,7 @@ static void init_call_elem(grpc_call_element *elem, call_data *calld = elem->call_data; calld->creds = NULL; calld->host = NULL; + calld->method = NULL; } /* Destructor for call_data */ @@ -230,6 +259,7 @@ static void init_channel_elem(grpc_channel_element *elem, channeld->md_ctx = metadata_context; channeld->authority_string = grpc_mdstr_from_string(channeld->md_ctx, ":authority"); + channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path"); channeld->error_msg_key = grpc_mdstr_from_string(channeld->md_ctx, "grpc-message"); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index a21c27bff946bef47ae9a2291fd7e8de9da8a8af..42d1a900fc52b69187a02b31033e18e4903e0898 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -33,6 +33,10 @@ #include "src/core/security/credentials.h" +#include <string.h> +#include <stdio.h> + +#include "src/core/json/json.h" #include "src/core/httpcli/httpcli.h" #include "src/core/iomgr/iomgr.h" #include "src/core/security/json_token.h" @@ -42,14 +46,9 @@ #include <grpc/support/sync.h> #include <grpc/support/time.h> -#include "src/core/json/json.h" - -#include <string.h> -#include <stdio.h> - /* -- Constants. -- */ -#define GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS 60 +#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60 #define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ @@ -113,6 +112,7 @@ int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) { } void grpc_credentials_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { if (creds == NULL || !grpc_credentials_has_request_metadata(creds) || @@ -122,7 +122,7 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds, } return; } - creds->vtable->get_request_metadata(creds, cb, user_data); + creds->vtable->get_request_metadata(creds, service_url, cb, user_data); } void grpc_server_credentials_release(grpc_server_credentials *creds) { @@ -288,6 +288,128 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( return &c->base; } +/* -- Jwt credentials -- */ + +typedef struct { + grpc_credentials base; + grpc_mdctx *md_ctx; + + /* Have a simple cache for now with just 1 entry. We could have a map based on + the service_url for a more sophisticated one. */ + gpr_mu cache_mu; + struct { + grpc_mdelem *jwt_md; + char *service_url; + gpr_timespec jwt_expiration; + } cached; + + grpc_auth_json_key key; + gpr_timespec jwt_lifetime; +} grpc_jwt_credentials; + +static void jwt_reset_cache(grpc_jwt_credentials *c) { + if (c->cached.jwt_md != NULL) { + grpc_mdelem_unref(c->cached.jwt_md); + c->cached.jwt_md = NULL; + } + if (c->cached.service_url != NULL) { + gpr_free(c->cached.service_url); + c->cached.service_url = NULL; + } + c->cached.jwt_expiration = gpr_inf_past; +} + +static void jwt_destroy(grpc_credentials *creds) { + grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds; + grpc_auth_json_key_destruct(&c->key); + jwt_reset_cache(c); + gpr_mu_destroy(&c->cache_mu); + grpc_mdctx_unref(c->md_ctx); + gpr_free(c); +} + +static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; } + +static int jwt_has_request_metadata_only(const grpc_credentials *creds) { + return 1; +} + + +static void jwt_get_request_metadata(grpc_credentials *creds, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds; + gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, + 0}; + + /* See if we can return a cached jwt. */ + grpc_mdelem *jwt_md = NULL; + { + gpr_mu_lock(&c->cache_mu); + if (c->cached.service_url != NULL && + !strcmp(c->cached.service_url, service_url) && + c->cached.jwt_md != NULL && + (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()), + refresh_threshold) > 0)) { + jwt_md = grpc_mdelem_ref(c->cached.jwt_md); + } + gpr_mu_unlock(&c->cache_mu); + } + + if (jwt_md == NULL) { + char *jwt = NULL; + /* Generate a new jwt. */ + gpr_mu_lock(&c->cache_mu); + jwt_reset_cache(c); + jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL); + if (jwt != NULL) { + char *md_value; + gpr_asprintf(&md_value, "Bearer %s", jwt); + gpr_free(jwt); + c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime); + c->cached.service_url = gpr_strdup(service_url); + c->cached.jwt_md = grpc_mdelem_from_strings( + c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, md_value); + gpr_free(md_value); + jwt_md = grpc_mdelem_ref(c->cached.jwt_md); + } + gpr_mu_unlock(&c->cache_mu); + } + + if (jwt_md != NULL) { + cb(user_data, &jwt_md, 1, GRPC_CREDENTIALS_OK); + grpc_mdelem_unref(jwt_md); + } else { + cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); + } +} + +static grpc_credentials_vtable jwt_vtable = { + jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, + jwt_get_request_metadata}; + +grpc_credentials *grpc_jwt_credentials_create(const char *json_key, + gpr_timespec token_lifetime) { + grpc_jwt_credentials *c; + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key); + if (!grpc_auth_json_key_is_valid(&key)) { + gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); + return NULL; + } + c = gpr_malloc(sizeof(grpc_jwt_credentials)); + memset(c, 0, sizeof(grpc_jwt_credentials)); + c->base.type = GRPC_CREDENTIALS_TYPE_JWT; + gpr_ref_init(&c->base.refcount, 1); + c->base.vtable = &jwt_vtable; + c->md_ctx = grpc_mdctx_create(); + c->key = key; + c->jwt_lifetime = token_lifetime; + gpr_mu_init(&c->cache_mu); + jwt_reset_cache(c); + return &c->base; +} + /* -- Oauth2TokenFetcher credentials -- */ /* This object is a base for credentials that need to acquire an oauth2 token @@ -439,10 +561,11 @@ static void on_oauth2_token_fetcher_http_response( } static void oauth2_token_fetcher_get_request_metadata( - grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials *creds, const char *service_url, + grpc_credentials_metadata_cb cb, void *user_data) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; - gpr_timespec refresh_threshold = {GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS, + gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, 0}; grpc_mdelem *cached_access_token_md = NULL; { @@ -535,7 +658,8 @@ static void service_account_fetch_oauth2( "application/x-www-form-urlencoded"}; grpc_httpcli_request request; char *body = NULL; - char *jwt = grpc_jwt_encode_and_sign(&c->key, c->scope, c->token_lifetime); + char *jwt = grpc_jwt_encode_and_sign(&c->key, GRPC_JWT_OAUTH2_AUDIENCE, + c->token_lifetime, c->scope); if (jwt == NULL) { grpc_httpcli_response response; memset(&response, 0, sizeof(grpc_httpcli_response)); @@ -616,6 +740,7 @@ void on_simulated_token_fetch_done(void *user_data, int success) { } static void fake_oauth2_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; @@ -709,6 +834,7 @@ typedef struct { size_t creds_index; grpc_mdelem **md_elems; size_t num_md; + char *service_url; void *user_data; grpc_credentials_metadata_cb cb; } grpc_composite_credentials_metadata_context; @@ -754,6 +880,7 @@ static void composite_md_context_destroy( grpc_mdelem_unref(ctx->md_elems[i]); } gpr_free(ctx->md_elems); + if (ctx->service_url != NULL) gpr_free(ctx->service_url); gpr_free(ctx); } @@ -783,8 +910,8 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, grpc_credentials *inner_creds = ctx->composite_creds->inner.creds_array[ctx->creds_index++]; if (grpc_credentials_has_request_metadata(inner_creds)) { - grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, - ctx); + grpc_credentials_get_request_metadata(inner_creds, ctx->service_url, + composite_metadata_cb, ctx); return; } } @@ -795,6 +922,7 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, } static void composite_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_composite_credentials *c = (grpc_composite_credentials *)creds; @@ -805,14 +933,15 @@ static void composite_get_request_metadata(grpc_credentials *creds, } ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context)); memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context)); + ctx->service_url = gpr_strdup(service_url); ctx->user_data = user_data; ctx->cb = cb; ctx->composite_creds = c; while (ctx->creds_index < c->inner.num_creds) { grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++]; if (grpc_credentials_has_request_metadata(inner_creds)) { - grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, - ctx); + grpc_credentials_get_request_metadata(inner_creds, service_url, + composite_metadata_cb, ctx); return; } } @@ -916,6 +1045,7 @@ static int iam_has_request_metadata_only(const grpc_credentials *creds) { } static void iam_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_iam_credentials *c = (grpc_iam_credentials *)creds; diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 614db96ad7ac705617e513f4307a42c7cd040742..7b8929492b24d73731860f5c700afb6fbf100d98 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -50,6 +50,7 @@ typedef enum { #define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" +#define GRPC_CREDENTIALS_TYPE_JWT "Jwt" #define GRPC_CREDENTIALS_TYPE_IAM "Iam" #define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" #define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity" @@ -71,6 +72,7 @@ typedef struct { int (*has_request_metadata)(const grpc_credentials *c); int (*has_request_metadata_only)(const grpc_credentials *c); void (*get_request_metadata)(grpc_credentials *c, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); } grpc_credentials_vtable; @@ -86,6 +88,7 @@ void grpc_credentials_unref(grpc_credentials *creds); int grpc_credentials_has_request_metadata(grpc_credentials *creds); int grpc_credentials_has_request_metadata_only(grpc_credentials *creds); void grpc_credentials_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); typedef struct { diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c index 20d62e2b438f4f2cce653c1cad128b98db55d597..26d57036a6d58d66b968faf499960fdf0f14ac0a 100644 --- a/src/core/security/json_token.c +++ b/src/core/security/json_token.c @@ -55,7 +55,6 @@ const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0}; #define GRPC_AUTH_JSON_KEY_TYPE_INVALID "invalid" #define GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT "service_account" -#define GRPC_JWT_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" #define GRPC_JWT_TYPE "JWT" @@ -171,8 +170,8 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) { /* --- jwt encoding and signature. --- */ static grpc_json *create_child(grpc_json *brother, grpc_json *parent, - const char *key, const char *value, - grpc_json_type type) { + const char *key, const char *value, + grpc_json_type type) { grpc_json *child = grpc_json_create(type); if (brother) brother->next = child; if (!parent->child) parent->child = child; @@ -182,14 +181,15 @@ static grpc_json *create_child(grpc_json *brother, grpc_json *parent, return child; } -static char *encoded_jwt_header(const char *algorithm) { +static char *encoded_jwt_header(const char *key_id, const char *algorithm) { grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *child = NULL; char *json_str = NULL; char *result = NULL; child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING); - create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); + child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); + create_child(child, json, "kid", key_id, GRPC_JSON_STRING); json_str = grpc_json_dump_to_string(json, 0); result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); @@ -199,7 +199,8 @@ static char *encoded_jwt_header(const char *algorithm) { } static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, - const char *scope, gpr_timespec token_lifetime) { + const char *audience, + gpr_timespec token_lifetime, const char *scope) { grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *child = NULL; char *json_str = NULL; @@ -217,8 +218,15 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, child = create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING); - child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); - child = create_child(child, json, "aud", GRPC_JWT_AUDIENCE, GRPC_JSON_STRING); + if (scope != NULL) { + child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); + } else { + /* Unscoped JWTs need a sub field. */ + child = create_child(child, json, "sub", json_key->client_email, + GRPC_JSON_STRING); + } + + child = create_child(child, json, "aud", audience, GRPC_JSON_STRING); child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER); create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER); @@ -300,14 +308,16 @@ end: } char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, - const char *scope, gpr_timespec token_lifetime) { + const char *audience, + gpr_timespec token_lifetime, const char *scope) { if (g_jwt_encode_and_sign_override != NULL) { - return g_jwt_encode_and_sign_override(json_key, scope, token_lifetime); + return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime, + scope); } else { const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM; char *to_sign = dot_concat_and_free_strings( - encoded_jwt_header(sig_algo), - encoded_jwt_claim(json_key, scope, token_lifetime)); + encoded_jwt_header(json_key->private_key_id, sig_algo), + encoded_jwt_claim(json_key, audience, token_lifetime, scope)); char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign); if (sig == NULL) { gpr_free(to_sign); diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h index 5a9b2dab4b3df82f48f153be865a5e23d5b6f64d..1ef9682f528cbcb78c77e2b2f7f0c0458ea85ca1 100644 --- a/src/core/security/json_token.h +++ b/src/core/security/json_token.h @@ -37,6 +37,10 @@ #include <grpc/support/slice.h> #include <openssl/rsa.h> +/* --- Constants. --- */ + +#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" + /* --- auth_json_key parsing. --- */ typedef struct { @@ -61,14 +65,15 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key); /* --- json token encoding and signing. --- */ /* Caller is responsible for calling gpr_free on the returned value. May return - NULL on invalid input. */ + NULL on invalid input. The scope parameter may be NULL. */ char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, - const char *scope, gpr_timespec token_lifetime); + const char *audience, + gpr_timespec token_lifetime, const char *scope); /* Override encode_and_sign function for testing. */ typedef char *(*grpc_jwt_encode_and_sign_override)( - const grpc_auth_json_key *json_key, const char *scope, - gpr_timespec token_lifetime); + const grpc_auth_json_key *json_key, const char *audience, + gpr_timespec token_lifetime, const char *scope); /* Set a custom encode_and_sign override for testing. */ void grpc_jwt_encode_and_sign_set_override( diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 37a312bc812ad0d62858d04fc837e7442b4c39c6..71bd06b271dc56731f8716bc994f04ead8c2904e 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -238,6 +238,7 @@ grpc_channel_security_context *grpc_fake_channel_security_context_create( gpr_malloc(sizeof(grpc_fake_channel_security_context)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.is_client_side = 1; + c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.base.vtable = &fake_channel_vtable; GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); @@ -250,6 +251,7 @@ grpc_security_context *grpc_fake_server_security_context_create(void) { grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context)); gpr_ref_init(&c->refcount, 1); c->vtable = &fake_server_vtable; + c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; return c; } @@ -458,6 +460,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; c->base.base.is_client_side = 1; + c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; if (target_name != NULL) { @@ -525,6 +528,7 @@ grpc_security_status grpc_ssl_server_security_context_create( memset(c, 0, sizeof(grpc_ssl_server_security_context)); gpr_ref_init(&c->base.refcount, 1); + c->base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.vtable = &ssl_server_vtable; result = tsi_create_ssl_server_handshaker_factory( (const unsigned char **)config->pem_private_keys, diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 2b9610fac3168c8ef540909993cbd18841b0c2f2..40e2daceb80d2b816d523852bffe4117dd593d63 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -47,6 +47,11 @@ typedef enum { GRPC_SECURITY_ERROR } grpc_security_status; +/* --- URL schemes. --- */ + +#define GRPC_SSL_URL_SCHEME "https" +#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" + /* --- security_context object. --- A security context object represents away to configure the underlying @@ -72,6 +77,7 @@ struct grpc_security_context { const grpc_security_context_vtable *vtable; gpr_refcount refcount; int is_client_side; + const char *url_scheme; }; /* Increments the refcount. */ diff --git a/src/core/support/cpu_windows.c b/src/core/support/cpu_windows.c index 9a460cc4844554bdedb9dbcf94565a4a4cd91ad7..cb454ccd3beed4f732f484b2f0a8088e89d8a7fb 100644 --- a/src/core/support/cpu_windows.c +++ b/src/core/support/cpu_windows.c @@ -35,8 +35,6 @@ #ifdef GPR_WIN32 -#include "src/core/support/cpu.h" - #include <grpc/support/log.h> unsigned gpr_cpu_num_cores(void) { diff --git a/src/core/support/host_port.c b/src/core/support/host_port.c index 379d30b045628aec4fc106eef7aa9f2b2a136718..fa49f1a33af016b0154f17e253c01b6acab76870 100644 --- a/src/core/support/host_port.c +++ b/src/core/support/host_port.c @@ -36,6 +36,7 @@ #include <string.h> #include "src/core/support/string.h" +#include <grpc/support/alloc.h> #include <grpc/support/log.h> int gpr_join_host_port(char **out, const char *host, int port) { @@ -47,3 +48,60 @@ int gpr_join_host_port(char **out, const char *host, int port) { return gpr_asprintf(out, "%s:%d", host, port); } } + +void gpr_split_host_port(const char *name, char **host, char **port) { + const char *host_start; + size_t host_len; + const char *port_start; + + *host = NULL; + *port = NULL; + + if (name[0] == '[') { + /* Parse a bracketed host, typically an IPv6 literal. */ + const char *rbracket = strchr(name, ']'); + if (rbracket == NULL) { + /* Unmatched [ */ + return; + } + if (rbracket[1] == '\0') { + /* ]<end> */ + port_start = NULL; + } else if (rbracket[1] == ':') { + /* ]:<port?> */ + port_start = rbracket + 2; + } else { + /* ]<invalid> */ + return; + } + host_start = name + 1; + host_len = rbracket - host_start; + if (memchr(host_start, ':', host_len) == NULL) { + /* Require all bracketed hosts to contain a colon, because a hostname or + IPv4 address should never use brackets. */ + return; + } + } else { + const char *colon = strchr(name, ':'); + if (colon != NULL && strchr(colon + 1, ':') == NULL) { + /* Exactly 1 colon. Split into host:port. */ + host_start = name; + host_len = colon - name; + port_start = colon + 1; + } else { + /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ + host_start = name; + host_len = strlen(name); + port_start = NULL; + } + } + + /* Allocate return values. */ + *host = gpr_malloc(host_len + 1); + memcpy(*host, host_start, host_len); + (*host)[host_len] = '\0'; + + if (port_start != NULL) { + *port = gpr_strdup(port_start); + } +} diff --git a/src/core/surface/init.c b/src/core/surface/init.c index fa4614abc84e524941dea85f1eede74a90076198..2d8f36e9c2ff16cd2d9a098f73321ea35a15530c 100644 --- a/src/core/surface/init.c +++ b/src/core/surface/init.c @@ -40,7 +40,7 @@ static gpr_once g_init = GPR_ONCE_INIT; static gpr_mu g_init_mu; static int g_initializations; -static void do_init() { +static void do_init(void) { gpr_mu_init(&g_init_mu); g_initializations = 0; } diff --git a/src/core/surface/server.c b/src/core/surface/server.c index a95215c5de99fff7521389209a1731d0896f22d9..c99a1b4cc9c9c72c3c144607890f6a143b69ba39 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -291,7 +291,7 @@ static void orphan_channel(channel_data *chand) { static void finish_destroy_channel(void *cd, int success) { channel_data *chand = cd; grpc_server *server = chand->server; - grpc_channel_destroy(chand->channel); + grpc_channel_internal_unref(chand->channel); server_unref(server); } diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 982417ec8a41710c457e3a194d9b32f7ed9052f7..ccd8d0c3764f093aabaeb4338ea5f5316e19ecba 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -191,6 +191,7 @@ struct transport { gpr_uint8 writing; gpr_uint8 calling_back; gpr_uint8 destroying; + gpr_uint8 closed; error_state error_state; /* stream indexing */ @@ -416,6 +417,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, t->next_stream_id = is_client ? 1 : 2; t->last_incoming_stream_id = 0; t->destroying = 0; + t->closed = 0; t->is_client = is_client; t->outgoing_window = DEFAULT_WINDOW; t->incoming_window = DEFAULT_WINDOW; @@ -521,6 +523,8 @@ static void destroy_transport(grpc_transport *gt) { static void close_transport(grpc_transport *gt) { transport *t = (transport *)gt; gpr_mu_lock(&t->mu); + GPR_ASSERT(!t->closed); + t->closed = 1; if (t->ep) { grpc_endpoint_shutdown(t->ep); } diff --git a/templates/Makefile.template b/templates/Makefile.template index 0ac901f69bc1c8b002d10fb7b378eae1aeef149b..a93e23638df1292000dce387ceb0a2e53ff8bc8b 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -251,6 +251,7 @@ OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/ope ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/zlib.c -lz $(LDFLAGS) PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/perftools.c -lprofiler $(LDFLAGS) PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o /dev/null test/build/protobuf.cc -lprotobuf $(LDFLAGS) +PROTOC_CMD = which protoc PROTOC_CHECK_CMD = protoc --version | grep -q libprotoc.3 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) @@ -261,10 +262,11 @@ LIBS += profiler endif endif +HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false) ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false) -HAS_SYSTEM_PROTOBUF = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false) +HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY) else # override system libraries if the config requires a custom compiled library HAS_SYSTEM_OPENSSL_ALPN = false @@ -272,7 +274,12 @@ HAS_SYSTEM_ZLIB = false HAS_SYSTEM_PROTOBUF = false endif +HAS_PROTOC = $(shell $(PROTOC_CMD) && echo true || echo false) +ifeq ($(HAS_PROTOC),true) HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +else +HAS_VALID_PROTOC = false +endif ifeq ($(wildcard third_party/openssl/ssl/ssl.h),) HAS_EMBEDDED_OPENSSL_ALPN = false @@ -325,8 +332,8 @@ LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE)) ifeq ($(HAS_SYSTEM_PROTOBUF),false) ifeq ($(HAS_EMBEDDED_PROTOBUF),true) PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a -CPPFLAGS += -Ithird_party/protobuf/src -LDFLAGS += -L$(LIBDIR)/$(CONFIG)/protobuf +CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS) +LDFLAGS := -L$(LIBDIR)/$(CONFIG)/protobuf $(LDFLAGS) PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc else NO_PROTOBUF = true @@ -344,6 +351,13 @@ ifeq ($(MAKECMDGOALS),clean) NO_DEPS = true endif +INSTALL_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_SYSTEM_PROTOBUF_VERIFY),true) +INSTALL_OK = true +endif +endif + .SECONDARY = %.pb.h %.pb.cc PROTOC_PLUGINS =\ @@ -481,7 +495,7 @@ third_party/protobuf/configure: $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure $(E) "[MAKE] Building protobuf" - $(Q)(cd third_party/protobuf ; CC="$(CC)" CPPFLAGS="-fPIC" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="$(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static) + $(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="-fPIC $(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static) $(Q)$(MAKE) -C third_party/protobuf clean $(Q)$(MAKE) -C third_party/protobuf $(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf @@ -715,7 +729,7 @@ $(OBJDIR)/$(CONFIG)/%.o : %.cc $(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $< -install: install_c install_cxx install-plugins +install: install_c install_cxx install-plugins verify-install install_c: install-headers_c install-static_c install-shared_c @@ -810,6 +824,25 @@ else % endfor endif +verify-install: +ifeq ($(SYSTEM_OK),true) + @echo "Your system looks ready to go." + @echo +else + @echo "Your system doesn't have protoc 3.0.0+ installed. While this" + @echo "won't prevent grpc from working, you won't be able to compile" + @echo "and run any meaningful code with it." + @echo + @echo + @echo "Please download and install protobuf 3.0.0+ from:" + @echo + @echo " https://github.com/google/protobuf/releases" + @echo + @echo "Once you've done so, you can re-run this check by doing:" + @echo + @echo " make verify-install" +endif + clean: $(E) "[CLEAN] Cleaning build directories." $(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) diff --git a/test/core/security/create_jwt.c b/test/core/security/create_jwt.c new file mode 100644 index 0000000000000000000000000000000000000000..614dd1e50c66ad5126db9e21a7cc8bfc7cee70dc --- /dev/null +++ b/test/core/security/create_jwt.c @@ -0,0 +1,110 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <string.h> + +#include "src/core/security/credentials.h" +#include "src/core/security/json_token.h" +#include "src/core/support/file.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/cmdline.h> +#include <grpc/support/log.h> +#include <grpc/support/slice.h> + +void create_jwt(const char *json_key_file_path, const char *service_url, + const char *scope) { + grpc_auth_json_key key; + int ok = 0; + char *jwt; + gpr_slice json_key_data = gpr_load_file(json_key_file_path, &ok); + if (!ok) { + fprintf(stderr, "Could not read %s.\n", json_key_file_path); + exit(1); + } + key = grpc_auth_json_key_create_from_string( + (const char *)GPR_SLICE_START_PTR(json_key_data)); + gpr_slice_unref(json_key_data); + if (!grpc_auth_json_key_is_valid(&key)) { + fprintf(stderr, "Could not parse json key.\n"); + exit(1); + } + jwt = grpc_jwt_encode_and_sign( + &key, service_url == NULL ? GRPC_JWT_OAUTH2_AUDIENCE : service_url, + grpc_max_auth_token_lifetime, scope); + grpc_auth_json_key_destruct(&key); + if (jwt == NULL) { + fprintf(stderr, "Could not create JWT.\n"); + exit(1); + } + fprintf(stdout, "%s\n", jwt); + gpr_free(jwt); +} + +int main(int argc, char **argv) { + char *scope = NULL; + char *json_key_file_path = NULL; + char *service_url = NULL; + gpr_cmdline *cl = gpr_cmdline_create("create_jwt"); + gpr_cmdline_add_string(cl, "json_key", "File path of the json key.", + &json_key_file_path); + gpr_cmdline_add_string(cl, "scope", + "OPTIONAL Space delimited permissions. Mutually " + "exclusive with service_url", + &scope); + gpr_cmdline_add_string(cl, "service_url", + "OPTIONAL service URL. Mutually exclusive with scope.", + &service_url); + gpr_cmdline_parse(cl, argc, argv); + + if (json_key_file_path == NULL) { + fprintf(stderr, "Missing --json_key option.\n"); + exit(1); + } + if (scope != NULL) { + if (service_url != NULL) { + fprintf(stderr, + "Options --scope and --service_url are mutually exclusive.\n"); + exit(1); + } + } else if (service_url == NULL) { + fprintf(stderr, "Need one of --service_url or --scope options.\n"); + exit(1); + } + + create_jwt(json_key_file_path, service_url, scope); + + gpr_cmdline_destroy(cl); + return 0; +} diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index f911db6de1f33174029451b8103d78782e660692..91229c95c25115c7f7fde5be7a9fa3ffd2c40768 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -89,12 +89,17 @@ static const char test_user_data[] = "user data"; static const char test_scope[] = "perm1 perm2"; -static const char test_signed_jwt[] = "signed jwt"; +static const char test_signed_jwt[] = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM4YW" + "U0MDcyZTViYTdmZDkwODg2YzcifQ"; static const char expected_service_account_http_body_prefix[] = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" "assertion="; +static const char test_service_url[] = "https://foo.com/foo.v1"; +static const char other_test_service_url[] = "https://bar.com/bar.v1"; + static char *test_json_key_str(void) { size_t result_len = strlen(test_json_key_str_part1) + strlen(test_json_key_str_part2) + @@ -259,7 +264,8 @@ static void test_iam_creds(void) { test_iam_authorization_token, test_iam_authority_selector); GPR_ASSERT(grpc_credentials_has_request_metadata(creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds)); - grpc_credentials_get_request_metadata(creds, check_iam_metadata, creds); + grpc_credentials_get_request_metadata(creds, test_service_url, + check_iam_metadata, creds); } static void check_ssl_oauth2_composite_metadata( @@ -293,8 +299,9 @@ static void test_ssl_oauth2_composite_creds(void) { !strcmp(creds_array->creds_array[0]->type, GRPC_CREDENTIALS_TYPE_SSL)); GPR_ASSERT( !strcmp(creds_array->creds_array[1]->type, GRPC_CREDENTIALS_TYPE_OAUTH2)); - grpc_credentials_get_request_metadata( - composite_creds, check_ssl_oauth2_composite_metadata, composite_creds); + grpc_credentials_get_request_metadata(composite_creds, test_service_url, + check_ssl_oauth2_composite_metadata, + composite_creds); } static void check_ssl_oauth2_iam_composite_metadata( @@ -338,7 +345,7 @@ static void test_ssl_oauth2_iam_composite_creds(void) { !strcmp(creds_array->creds_array[1]->type, GRPC_CREDENTIALS_TYPE_OAUTH2)); GPR_ASSERT( !strcmp(creds_array->creds_array[2]->type, GRPC_CREDENTIALS_TYPE_IAM)); - grpc_credentials_get_request_metadata(composite_creds, + grpc_credentials_get_request_metadata(composite_creds, test_service_url, check_ssl_oauth2_iam_composite_metadata, composite_creds); } @@ -420,14 +427,14 @@ static void test_compute_engine_creds_success(void) { /* First request: http get should be called. */ grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, httpcli_post_should_not_be_called); - grpc_credentials_get_request_metadata(compute_engine_creds, + grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url, on_oauth2_creds_get_metadata_success, (void *)test_user_data); /* Second request: the cached token should be served directly. */ grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - grpc_credentials_get_request_metadata(compute_engine_creds, + grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url, on_oauth2_creds_get_metadata_success, (void *)test_user_data); @@ -442,7 +449,7 @@ static void test_compute_engine_creds_failure(void) { httpcli_post_should_not_be_called); GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds)); - grpc_credentials_get_request_metadata(compute_engine_creds, + grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url, on_oauth2_creds_get_metadata_failure, (void *)test_user_data); grpc_credentials_unref(compute_engine_creds); @@ -468,27 +475,29 @@ static void validate_jwt_encode_and_sign_params( !strcmp(json_key->client_email, "777-abaslkan11hlb6nmim3bpspl31ud@developer." "gserviceaccount.com")); - GPR_ASSERT(!strcmp(scope, test_scope)); + if (scope != NULL) GPR_ASSERT(!strcmp(scope, test_scope)); GPR_ASSERT(!gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime)); } static char *encode_and_sign_jwt_success(const grpc_auth_json_key *json_key, - const char *scope, - gpr_timespec token_lifetime) { + const char *audience, + gpr_timespec token_lifetime, + const char *scope) { validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime); return gpr_strdup(test_signed_jwt); } static char *encode_and_sign_jwt_failure(const grpc_auth_json_key *json_key, - const char *scope, - gpr_timespec token_lifetime) { + const char *audience, + gpr_timespec token_lifetime, + const char *scope) { validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime); return NULL; } static char *encode_and_sign_jwt_should_not_be_called( - const grpc_auth_json_key *json_key, const char *scope, - gpr_timespec token_lifetime) { + const grpc_auth_json_key *json_key, const char *audience, + gpr_timespec token_lifetime, const char *scope) { GPR_ASSERT("grpc_jwt_encode_and_sign should not be called" == NULL); } @@ -533,7 +542,7 @@ static int service_account_httpcli_post_failure( return 1; } -static void test_service_accounts_creds_success(void) { +static void test_service_account_creds_success(void) { char *json_key_string = test_json_key_str(); grpc_credentials *service_account_creds = grpc_service_account_credentials_create(json_key_string, test_scope, @@ -545,7 +554,7 @@ static void test_service_accounts_creds_success(void) { grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); grpc_httpcli_set_override(httpcli_get_should_not_be_called, service_account_httpcli_post_success); - grpc_credentials_get_request_metadata(service_account_creds, + grpc_credentials_get_request_metadata(service_account_creds, test_service_url, on_oauth2_creds_get_metadata_success, (void *)test_user_data); @@ -554,7 +563,7 @@ static void test_service_accounts_creds_success(void) { encode_and_sign_jwt_should_not_be_called); grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - grpc_credentials_get_request_metadata(service_account_creds, + grpc_credentials_get_request_metadata(service_account_creds, test_service_url, on_oauth2_creds_get_metadata_success, (void *)test_user_data); @@ -564,7 +573,7 @@ static void test_service_accounts_creds_success(void) { grpc_httpcli_set_override(NULL, NULL); } -static void test_service_accounts_creds_http_failure(void) { +static void test_service_account_creds_http_failure(void) { char *json_key_string = test_json_key_str(); grpc_credentials *service_account_creds = grpc_service_account_credentials_create(json_key_string, test_scope, @@ -575,7 +584,7 @@ static void test_service_accounts_creds_http_failure(void) { grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); grpc_httpcli_set_override(httpcli_get_should_not_be_called, service_account_httpcli_post_failure); - grpc_credentials_get_request_metadata(service_account_creds, + grpc_credentials_get_request_metadata(service_account_creds, test_service_url, on_oauth2_creds_get_metadata_failure, (void *)test_user_data); @@ -584,7 +593,7 @@ static void test_service_accounts_creds_http_failure(void) { grpc_httpcli_set_override(NULL, NULL); } -static void test_service_accounts_creds_signing_failure(void) { +static void test_service_account_creds_signing_failure(void) { char *json_key_string = test_json_key_str(); grpc_credentials *service_account_creds = grpc_service_account_credentials_create(json_key_string, test_scope, @@ -595,13 +604,88 @@ static void test_service_accounts_creds_signing_failure(void) { grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure); grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - grpc_credentials_get_request_metadata(service_account_creds, + grpc_credentials_get_request_metadata(service_account_creds, test_service_url, on_oauth2_creds_get_metadata_failure, (void *)test_user_data); gpr_free(json_key_string); grpc_credentials_unref(service_account_creds); grpc_httpcli_set_override(NULL, NULL); + grpc_jwt_encode_and_sign_set_override(NULL); +} + +static void on_jwt_creds_get_metadata_success( + void *user_data, grpc_mdelem **md_elems, size_t num_md, + grpc_credentials_status status) { + char *expected_md_value; + gpr_asprintf(&expected_md_value, "Bearer %s", test_signed_jwt); + GPR_ASSERT(status == GRPC_CREDENTIALS_OK); + GPR_ASSERT(num_md == 1); + GPR_ASSERT( + !strcmp(grpc_mdstr_as_c_string(md_elems[0]->key), "Authorization")); + GPR_ASSERT( + !strcmp(grpc_mdstr_as_c_string(md_elems[0]->value), expected_md_value)); + GPR_ASSERT(user_data != NULL); + GPR_ASSERT(!strcmp((const char *)user_data, test_user_data)); + gpr_free(expected_md_value); +} + +static void on_jwt_creds_get_metadata_failure( + void *user_data, grpc_mdelem **md_elems, size_t num_md, + grpc_credentials_status status) { + GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR); + GPR_ASSERT(num_md == 0); + GPR_ASSERT(user_data != NULL); + GPR_ASSERT(!strcmp((const char *)user_data, test_user_data)); +} + +static void test_jwt_creds_success(void) { + char *json_key_string = test_json_key_str(); + grpc_credentials *jwt_creds = grpc_jwt_credentials_create( + json_key_string, grpc_max_auth_token_lifetime); + GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds)); + GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds)); + + /* First request: jwt_encode_and_sign should be called. */ + grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); + grpc_credentials_get_request_metadata(jwt_creds, test_service_url, + on_jwt_creds_get_metadata_success, + (void *)test_user_data); + + /* Second request: the cached token should be served directly. */ + grpc_jwt_encode_and_sign_set_override( + encode_and_sign_jwt_should_not_be_called); + grpc_credentials_get_request_metadata(jwt_creds, test_service_url, + on_jwt_creds_get_metadata_success, + (void *)test_user_data); + + /* Third request: Different service url so jwt_encode_and_sign should be + called again (no caching). */ + grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); + grpc_credentials_get_request_metadata(jwt_creds, other_test_service_url, + on_jwt_creds_get_metadata_success, + (void *)test_user_data); + + gpr_free(json_key_string); + grpc_credentials_unref(jwt_creds); + grpc_jwt_encode_and_sign_set_override(NULL); +} + +static void test_jwt_creds_signing_failure(void) { + char *json_key_string = test_json_key_str(); + grpc_credentials *jwt_creds = grpc_jwt_credentials_create( + json_key_string, grpc_max_auth_token_lifetime); + GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds)); + GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds)); + + grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure); + grpc_credentials_get_request_metadata(jwt_creds, test_service_url, + on_jwt_creds_get_metadata_failure, + (void *)test_user_data); + + gpr_free(json_key_string); + grpc_credentials_unref(jwt_creds); + grpc_jwt_encode_and_sign_set_override(NULL); } int main(int argc, char **argv) { @@ -618,8 +702,10 @@ int main(int argc, char **argv) { test_ssl_oauth2_iam_composite_creds(); test_compute_engine_creds_success(); test_compute_engine_creds_failure(); - test_service_accounts_creds_success(); - test_service_accounts_creds_http_failure(); - test_service_accounts_creds_signing_failure(); + test_service_account_creds_success(); + test_service_account_creds_http_failure(); + test_service_account_creds_signing_failure(); + test_jwt_creds_success(); + test_jwt_creds_signing_failure(); return 0; } diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c index 6315087448947b0644e7b31e4a99044e14e41941..748a5982fdeb41343874c06b523c54e96147df37 100644 --- a/test/core/security/fetch_oauth2.c +++ b/test/core/security/fetch_oauth2.c @@ -139,7 +139,7 @@ int main(int argc, char **argv) { } } else { if (json_key_file_path == NULL) { - gpr_log(GPR_ERROR, "missing --json_key option."); + gpr_log(GPR_ERROR, "Missing --json_key option."); exit(1); } if (scope == NULL) { @@ -162,7 +162,7 @@ int main(int argc, char **argv) { gpr_cv_init(&sync.cv); sync.is_done = 0; - grpc_credentials_get_request_metadata(creds, on_oauth2_response, &sync); + grpc_credentials_get_request_metadata(creds, "", on_oauth2_response, &sync); gpr_mu_lock(&sync.mu); while (!sync.is_done) gpr_cv_wait(&sync.cv, &sync.mu, gpr_inf_future); diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c index 8615fca5fbb4346e2dee1eef096b985215e3d55c..eed0fdf33210cf589060d5d7ce4d3931d0c23314 100644 --- a/test/core/security/json_token_test.c +++ b/test/core/security/json_token_test.c @@ -76,6 +76,8 @@ static const char test_json_key_str_part3[] = static const char test_scope[] = "myperm1 myperm2"; +static const char test_service_url[] = "https://foo.com/foo.v1"; + static char *test_json_key_str(const char *bad_part3) { const char *part3 = bad_part3 != NULL ? bad_part3 : test_json_key_str_part3; size_t result_len = strlen(test_json_key_str_part1) + @@ -229,12 +231,15 @@ static void check_jwt_header(grpc_json *header) { grpc_json *ptr; grpc_json *alg = NULL; grpc_json *typ = NULL; + grpc_json *kid = NULL; for (ptr = header->child; ptr; ptr = ptr->next) { if (strcmp(ptr->key, "alg") == 0) { alg = ptr; } else if (strcmp(ptr->key, "typ") == 0) { typ = ptr; + } else if (strcmp(ptr->key, "kid") == 0) { + kid = ptr; } } GPR_ASSERT(alg != NULL); @@ -244,9 +249,14 @@ static void check_jwt_header(grpc_json *header) { GPR_ASSERT(typ != NULL); GPR_ASSERT(typ->type == GRPC_JSON_STRING); GPR_ASSERT(!strcmp(typ->value, "JWT")); + + GPR_ASSERT(kid != NULL); + GPR_ASSERT(kid->type == GRPC_JSON_STRING); + GPR_ASSERT(!strcmp(kid->value, "e6b5137873db8d2ef81e06a47289e6434ec8a165")); } -static void check_jwt_claim(grpc_json *claim) { +static void check_jwt_claim(grpc_json *claim, const char *expected_audience, + const char *expected_scope) { gpr_timespec expiration = {0, 0}; gpr_timespec issue_time = {0, 0}; gpr_timespec parsed_lifetime; @@ -255,11 +265,14 @@ static void check_jwt_claim(grpc_json *claim) { grpc_json *aud = NULL; grpc_json *exp = NULL; grpc_json *iat = NULL; + grpc_json *sub = NULL; grpc_json *ptr; for (ptr = claim->child; ptr; ptr = ptr->next) { if (strcmp(ptr->key, "iss") == 0) { iss = ptr; + } else if (strcmp(ptr->key, "sub") == 0) { + sub = ptr; } else if (strcmp(ptr->key, "scope") == 0) { scope = ptr; } else if (strcmp(ptr->key, "aud") == 0) { @@ -278,14 +291,22 @@ static void check_jwt_claim(grpc_json *claim) { iss->value, "777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount.com")); - GPR_ASSERT(scope != NULL); - GPR_ASSERT(scope->type == GRPC_JSON_STRING); - GPR_ASSERT(!strcmp(scope->value, test_scope)); + if (expected_scope != NULL) { + GPR_ASSERT(scope != NULL); + GPR_ASSERT(sub == NULL); + GPR_ASSERT(scope->type == GRPC_JSON_STRING); + GPR_ASSERT(!strcmp(scope->value, expected_scope)); + } else { + /* Claims without scope must have a sub. */ + GPR_ASSERT(scope == NULL); + GPR_ASSERT(sub != NULL); + GPR_ASSERT(sub->type == GRPC_JSON_STRING); + GPR_ASSERT(!strcmp(iss->value, sub->value)); + } GPR_ASSERT(aud != NULL); GPR_ASSERT(aud->type == GRPC_JSON_STRING); - GPR_ASSERT(!strcmp(aud->value, - "https://www.googleapis.com/oauth2/v3/token")); + GPR_ASSERT(!strcmp(aud->value, expected_audience)); GPR_ASSERT(exp != NULL); GPR_ASSERT(exp->type == GRPC_JSON_NUMBER); @@ -324,7 +345,28 @@ static void check_jwt_signature(const char *b64_signature, RSA *rsa_key, if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); } -static void test_jwt_encode_and_sign(void) { +static char *service_account_creds_jwt_encode_and_sign( + const grpc_auth_json_key *key) { + return grpc_jwt_encode_and_sign(key, GRPC_JWT_OAUTH2_AUDIENCE, + grpc_max_auth_token_lifetime, test_scope); +} + +static char *jwt_creds_jwt_encode_and_sign(const grpc_auth_json_key *key) { + return grpc_jwt_encode_and_sign(key, test_service_url, + grpc_max_auth_token_lifetime, NULL); +} + +static void service_account_creds_check_jwt_claim(grpc_json *claim) { + check_jwt_claim(claim, GRPC_JWT_OAUTH2_AUDIENCE, test_scope); +} + +static void jwt_creds_check_jwt_claim(grpc_json *claim) { + check_jwt_claim(claim, test_service_url, NULL); +} + +static void test_jwt_encode_and_sign( + char *(*jwt_encode_and_sign_func)(const grpc_auth_json_key *), + void (*check_jwt_claim_func)(grpc_json *)) { char *json_string = test_json_key_str(NULL); grpc_json *parsed_header = NULL; grpc_json *parsed_claim = NULL; @@ -333,8 +375,7 @@ static void test_jwt_encode_and_sign(void) { grpc_auth_json_key_create_from_string(json_string); const char *b64_signature; size_t offset = 0; - char *jwt = grpc_jwt_encode_and_sign(&json_key, test_scope, - grpc_max_auth_token_lifetime); + char *jwt = jwt_encode_and_sign_func(&json_key); const char *dot = strchr(jwt, '.'); GPR_ASSERT(dot != NULL); parsed_header = parse_json_part_from_jwt(jwt, dot - jwt, &scratchpad); @@ -346,9 +387,10 @@ static void test_jwt_encode_and_sign(void) { dot = strchr(jwt + offset, '.'); GPR_ASSERT(dot != NULL); - parsed_claim = parse_json_part_from_jwt(jwt + offset, dot - (jwt + offset), &scratchpad); + parsed_claim = + parse_json_part_from_jwt(jwt + offset, dot - (jwt + offset), &scratchpad); GPR_ASSERT(parsed_claim != NULL); - check_jwt_claim(parsed_claim); + check_jwt_claim_func(parsed_claim); offset = dot - jwt + 1; grpc_json_destroy(parsed_claim); gpr_free(scratchpad); @@ -363,6 +405,16 @@ static void test_jwt_encode_and_sign(void) { gpr_free(jwt); } +static void test_service_account_creds_jwt_encode_and_sign(void) { + test_jwt_encode_and_sign(service_account_creds_jwt_encode_and_sign, + service_account_creds_check_jwt_claim); +} + +static void test_jwt_creds_jwt_encode_and_sign(void) { + test_jwt_encode_and_sign(jwt_creds_jwt_encode_and_sign, + jwt_creds_check_jwt_claim); +} + int main(int argc, char **argv) { grpc_test_init(argc, argv); test_parse_json_key_success(); @@ -372,6 +424,7 @@ int main(int argc, char **argv) { test_parse_json_key_failure_no_client_email(); test_parse_json_key_failure_no_private_key_id(); test_parse_json_key_failure_no_private_key(); - test_jwt_encode_and_sign(); + test_service_account_creds_jwt_encode_and_sign(); + test_jwt_creds_jwt_encode_and_sign(); return 0; } diff --git a/vsprojects/vs2013/Grpc.mak b/vsprojects/vs2013/Grpc.mak index a629ef425ec3dd1c3f0d19e87b89240a16b45147..37bc9cb331036a111ba626ba43c16bbc223c04ce 100644 --- a/vsprojects/vs2013/Grpc.mak +++ b/vsprojects/vs2013/Grpc.mak @@ -418,6 +418,14 @@ grpc_completion_queue_test: grpc_completion_queue_test.exe echo Running grpc_completion_queue_test $(OUT_DIR)\grpc_completion_queue_test.exe +grpc_create_jwt.exe: grpc_test_util + echo Building grpc_create_jwt + $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\create_jwt.c + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_create_jwt.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\create_jwt.obj +grpc_create_jwt: grpc_create_jwt.exe + echo Running grpc_create_jwt + $(OUT_DIR)\grpc_create_jwt.exe + grpc_credentials_test.exe: grpc_test_util echo Building grpc_credentials_test $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\credentials_test.c diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj index b55c7f926bafe6be9640947696ba011b74d329ac..89c0de333c9ecc526b79dada47cd96acd1545032 100644 --- a/vsprojects/vs2013/grpc.vcxproj +++ b/vsprojects/vs2013/grpc.vcxproj @@ -283,7 +283,9 @@ </ClCompile> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> </ClCompile> - <ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c"> + </ClCompile> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c"> </ClCompile> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> </ClCompile> diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters index 9505c37ef4e99f795df487e534085f5d81fe82d7..a2d9f30eda750a0a65c5f083167c705dfe6f92d5 100644 --- a/vsprojects/vs2013/grpc.vcxproj.filters +++ b/vsprojects/vs2013/grpc.vcxproj.filters @@ -145,7 +145,10 @@ <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <Filter>src\core\iomgr</Filter> </ClCompile> - <ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c"> + <Filter>src\core\iomgr</Filter> + </ClCompile> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c"> <Filter>src\core\iomgr</Filter> </ClCompile> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> diff --git a/vsprojects/vs2013/grpc_shared.vcxproj b/vsprojects/vs2013/grpc_shared.vcxproj index dfb08991380606d4eaf1ce8a7b8174a4b662b418..81a280d912a2c274bdae07f29b58c0ce362252a0 100644 --- a/vsprojects/vs2013/grpc_shared.vcxproj +++ b/vsprojects/vs2013/grpc_shared.vcxproj @@ -287,7 +287,9 @@ </ClCompile> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> </ClCompile> - <ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c"> + </ClCompile> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c"> </ClCompile> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> </ClCompile> diff --git a/vsprojects/vs2013/grpc_shared.vcxproj.filters b/vsprojects/vs2013/grpc_shared.vcxproj.filters index 9505c37ef4e99f795df487e534085f5d81fe82d7..a2d9f30eda750a0a65c5f083167c705dfe6f92d5 100644 --- a/vsprojects/vs2013/grpc_shared.vcxproj.filters +++ b/vsprojects/vs2013/grpc_shared.vcxproj.filters @@ -145,7 +145,10 @@ <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <Filter>src\core\iomgr</Filter> </ClCompile> - <ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c"> + <Filter>src\core\iomgr</Filter> + </ClCompile> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c"> <Filter>src\core\iomgr</Filter> </ClCompile> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj index 74fc6c96ece59982801bb8419ddd9be746d3333a..0c81ec4768bc0a8ea2047ff92f888bfd5b33b920 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj @@ -232,7 +232,9 @@ </ClCompile> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> </ClCompile> - <ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c"> + </ClCompile> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c"> </ClCompile> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> </ClCompile> diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters index ea34d210bfe55c911f9ded24d8bcc9bf1d9d813b..4b5370a57351f6f808b5887e44a66585e9b4c409 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters @@ -91,7 +91,10 @@ <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <Filter>src\core\iomgr</Filter> </ClCompile> - <ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c"> + <Filter>src\core\iomgr</Filter> + </ClCompile> + <ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c"> <Filter>src\core\iomgr</Filter> </ClCompile> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">